Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ESFluteによるElasticsearchでのO/Rマッパーを用いた開発

 ESFluteによるElasticsearchでのO/Rマッパーを用いた開発

Shinsuke Sugaya

November 27, 2016
Tweet

More Decks by Shinsuke Sugaya

Other Decks in Programming

Transcript

  1. DBFluteフェス 2016 ▪ 名前: 菅谷信介 ▪ オープンソース活動: ➔ Fess, DBFlute関連,

    Apache Portals, Codehaus, Seasar2,... ▪ Blog: http://www.chazine.com/ ▪ Twitter: https://twitter.com/shinsuke_sugaya/ 自己紹介 2
  2. DBFluteフェス 2016 ▪ DBFluteのElasticsearch版 ➔ CBやBhvが使えます ▪ インデックス設定情報からソースの自動生成 ▪ Elasticsearch

    1.7と2.xに対応 ➔ 5.x系対応は近日対応予定 ➔ バージョンごとにブランチ管理 ▪ DBFlute本体にバンドル ➔ 将来的には単独の配布にしたい ▪ Exampleプロジェクト https://github.com/lastaflute/lastaflute-example-waterfront テストコードもあります! ESFluteとは 8
  3. DBFluteフェス 2016 分散環境的な話… ▪ 基本的な構成要素 ➔ クラスタ ➔ ノード ➔

    インデックス ➔ シャード ▪ クラスタは複数のノードから構成される ▪ クラスタは複数のインデックスを保持できる ▪ インデックスは複数のシャードから構成される ▪ シャードは1つのプライマリと複数のレプリカで構成 される ▪ ノードは複数のシャードを保持できる 構成要素 12
  4. DBFluteフェス 2016 構成要素 13 ノード1 ノード3 ノード2 ノード4 インデックス1 シャード1

    インデックス1 シャード2 インデックス2 シャード2 インデックス1 シャード2 インデックス2 シャード1 インデックス1 シャード3 インデックス1 シャード1 インデックス2 シャード1 インデックス1 シャード4 インデックス1 シャード3 インデックス2 シャード2 インデックス1 シャード4 クラスタ
  5. DBFluteフェス 2016 ▪ インデックス名を指定してPUTでリクエスト $ curl -XPUT ‘localhost:9200/company -d ‘{

    “settings”: { …(Analyzer等のインデックス関連の指定)... }, “mappings”: { …(スキーマなど指定)... } }’ インデックス作成 18
  6. DBFluteフェス 2016 ▪ PUT/POSTでJSONオブジェクトをリクエスト ▪ パスは /インデックス名/タイプ名/ID $ curl -XPUT

    ‘localhost:9200/company/employee/1’ -d ‘{ “employee_id”: ”00001”, “first_name”: “Taro”, “last_name”: “Suzuki” }’ ドキュメントの追加 19
  7. DBFluteフェス 2016 ▪ 文字列: string ▪ 数値: long, integer, short,

    byte, double, float ▪ 日付: date ▪ 論理値: boolean ▪ バイナリ: binary ▪ その他: object, geo_point, ip,... ESFluteではバイナリやその他の型はまだ未対応 基本的な型 21
  8. DBFluteフェス 2016 ▪ テキストを分解して単語群を生成する ▪ CharFilter/Tokenizer/TokenFilterで構成される ▪ Luceneのインターフェース ▪ 組み合わせることで自由自在の解析可能

    ▪ インデックスの生成時に設定する 「今日の天気は晴れです」      ↓ 「今日」「天気」「晴れ」 Analyzer 23
  9. DBFluteフェス 2016 Analyzer 24 「東京スカイツリーの①番出口」 CharFilter (文字単位で変換) TokenFilter (単語単位で変換) Tokenizer

    (単語に分割) 「東京スカイツリーの1番出口」 「東京」「スカイツリー」「の」「1番」「出口」 「東京」「スカイツリ」「1番」「出口」 Analyzer
  10. DBFluteフェス 2016 ▪ 構造的なQuery DSLを利用 ▪ HTTPまたはTransportでリクエスト ➔現時点ではESFluteはTransportを利用 ▪ 様々なクエリーをサポート(aggs,

    geo,...) $ curl -XPOST ‘localhost:9200/company/_search -d ‘{ “query” : { "match_phrase" : { "content" : "fess" } }, “size”: 10 } 検索クエリー 25
  11. DBFluteフェス 2016 ▪ DBFluteの基本的な設定を作成 例(Mavenプロジェクトなら): $ mvn dbflute:download $ mvn

    dbflute:create-client http://dbflute.seasar.org/ja/environment/setup/index.html DBFluteの環境準備 27
  12. DBFluteフェス 2016 ▪ ESFluteはインデックス情報を利用 ▪ Elasticsearchのインデックス情報をファイルに保存 する $ curl -XGET

    localhost:9200/[index] > dbflute_[project]/playes/index/[index].json インデックス情報の保存 28
  13. DBFluteフェス 2016 ▪ dbflute_[project]/dfprop/esfluteMap.dfprop esfluteMap.dfprop map:{ # base package of

    generated classes ; basePackage = org.docksidestage.esflute # base path to JSON resource, URL or relative path ; basePath = ./playes/index ←インデックスの設定情報ファイルを置いておくディレクトリ # settings for indexes ; indexMap = map:{ ; maihama = map:{ ←インデックス名 ; package = maihama } } # version for elasticsearch's jar file (no version means latest) ; elasticsearchVersion = 2.3.0 } 29
  14. DBFluteフェス 2016 必要に応じて… コンポーネント定義 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE components PUBLIC

    "-//DBFLUTE//DTD LastaDi 1.0//EN" "http://dbflute.org/meta/lastadi10.dtd"> <components> <include path="esclient.xml"/> <!-- The components of DBFlute Runtime. --> <component name="behaviorCommandInvoker" class="org.dbflute.bhv.core.BehaviorCommandInvoker"/> <!-- The components of Behavior. --> <component name="userBhv" class="org.codelibs.fess.es.user.exbhv.UserBhv"/> <component name="roleBhv" class="org.codelibs.fess.es.user.exbhv.RoleBhv"/> <component name="groupBhv" class="org.codelibs.fess.es.user.exbhv.GroupBhv"/> </components> 31
  15. DBFluteフェス 2016 ▪ Bhvインスタンスでinsert ➔ オプションで即時反映も可能 ➔ 更新も同じ感じで データの追加 @Resource

    private ProductBhv productBhv; … Product product = new Product(); product.setProductDescription(form.productDescription); product.setProductCategoryCode(form.productCategoryCode); ... productBhv.insert(product, op -> { op.setRefresh(true); // 即時反映 }); 33
  16. DBFluteフェス 2016 ▪ Bhvインスタンスでdelete ➔ オプションで即時反映も可能 ➔ Delete By Queryも内部的にScrollで実現

    データの削除 productBhv.selectByPK(form.productId).ifPresent(entity -> { productBhv.delete(entity, op -> { op.setRefresh(true); }); }).orElse(() -> { throw404("Not found the product: " + form.productId); }); 34
  17. DBFluteフェス 2016 ▪ BhvでselectPage, selectList, selectByPK, selectCount, selectEntity, selectCursorに対応 ▪

    CBで検索条件を指定 ➔ pagingやaddOrder〜も対応 ▪ 戻り値はDBFluteと同様 検索系メソッド PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().matchAll(); cb.query().addOrderBy_Id_Asc(); cb.paging(5, 1); }); 37
  18. DBFluteフェス 2016 ▪ 全件にマッチするクエリー ➔ count等で利用 Match All Query 38

    PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().matchAll(); cb.query().addOrderBy_Id_Asc(); cb.paging(5, 1); });
  19. DBFluteフェス 2016 ▪ 解析された文字列にマッチするクエリー ➔ 全文検索で利用 ▪ 解析された文字列にマッチするので、以下のflute はFluteにも一致する ➔

    フレーズとしてはマッチしない ➔ 日本語bi-gramでは期待通りの結果にならない Match Query PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().setProductName_Match("flute"); cb.query().addOrderBy_Id_Asc(); cb.paging(5, 1); }); 39
  20. DBFluteフェス 2016 ▪ 解析された文字列のフレーズでマッチする ➔ タームの順番も含めて一致する ➔ 日本語の場合、ほぼこのクエリーを利用する ➔ Match

    Queryの場合、並び順に関係なく、ヒットする Match Phrase Query PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().setProductName_MatchPhrase("Low Price Flute"); cb.query().addOrderBy_Id_Asc(); cb.paging(5, 1); }); 40
  21. DBFluteフェス 2016 ▪ フレーズでの前方一致にマッチするクエリー ➔ Match Phraseの前方一致版クエリー ➔ 入力された文字列の最後の単語では前方一致を行う Match

    Phrase Prefix Query PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().setProductName_MatchPhrasePrefix("Low P", op -> { op.maxExpansions(10); }); cb.query().addOrderBy_Id_Asc(); cb.paging(5, 1); }); 41
  22. DBFluteフェス 2016 ▪ 頻出単語を除外してマッチするクエリー ▪ 頻度の指定が可能 ➔ 以下の例だと、0.1%より多く登場する単語を除外 Common Terms

    Query PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().setProductName_CommonTerms("What is Grand Piano", op -> { op.cutoffFrequency(0.001f); }); cb.query().addOrderBy_Id_Asc(); cb.paging(5, 1); }); 42
  23. DBFluteフェス 2016 ▪ 検索クエリーを文字列で指定するクエリー ➔ サーチエンジンに利用 ➔ Luceneの構文に従う ▪ 入力によって幅広い検索が可能

    ➔ 範囲検索、あいまい検索、正規表現等 Query String Query PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().queryString("Flute OR Piano", op -> { op.defaultField("product_name"); }); cb.query().addOrderBy_Id_Asc(); cb.paging(5, 1); }); 43
  24. DBFluteフェス 2016 ▪ 指定された値にマッチするクエリー ➔ テキスト解析はされず、値そのものにマッチする ➔ 区分値など、値のまま、インデックスしたものの検索 ➔ not_analyzedのフィールドに対して利用

    ➔ set〜_EqualはTerm Queryを利用 Term Query PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().setProductHandleCode_Term("FLUTE-01", op -> { op.queryName("exact_value"); }); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); 44
  25. DBFluteフェス 2016 ▪ Term Queryの複数指定版クエリー ➔ 複数の値にマッチする検索をする ➔ set〜_InScopeはTerms Queryを利用

    Terms Query PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { ArrayList<String> terms = new ArrayList<>(); terms.add("piano"); terms.add("flute"); cb.query().setProductName_Terms(terms); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); 45
  26. DBFluteフェス 2016 ▪ 範囲指定検索 ➔ 数値や日付を範囲指定する場合に利用する ➔ 通常のCBと同様 Range Query

    PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().setLatestPurchaseDate_GreaterEqual( LocalDateTime.of(2014, 1, 1, 0, 0, 0)); cb.query().addOrderBy_LatestPurchaseDate_Asc(); cb.paging(5, 1); }); 46
  27. DBFluteフェス 2016 ▪ フィールドに値が存在するものにマッチする ➔ 値があるものを検索する場合に利用する ▪ 存在しないものを検索したい場合 ➔ boolのmust_notのexistsクエリーを利用する

    ▪ null値はElasticsearch上で設定可能 Exists Query PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().setProductName_Exists(); cb.query().addOrderBy_ProductName_Asc(); cb.paging(5, 1); }); 47
  28. DBFluteフェス 2016 ▪ 前方一致のクエリー ➔ Term Queryの前方一致検索版 ➔ テキスト解析されないフィールドで利用する Prefix

    Query PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().setProductCategory_Prefix("Ins"); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); 48
  29. DBFluteフェス 2016 ▪ ワイルドカードによる検索 ➔ Term Queryのワイルドカード検索版 ➔ テキスト解析されないフィールドで利用する Wildcard

    Query PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().setProductCategoryCode_Wildcard("H?B"); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); 49
  30. DBFluteフェス 2016 ▪ 正規表現による検索 ➔ Term Queryで正規表現を利用したい場合に利用する ➔ 遅い Regexp

    Query PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().setProductHandleCode_Regexp("[A-Z]{5}-<01-02>"); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); 50
  31. DBFluteフェス 2016 ▪ あいまい検索 ➔ レーベンシュタイン距離による検索 ➔ 類似する単語を見つける Fuzzy Query

    PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().setProductCategory_Fuzzy("Insturument"); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); 51
  32. DBFluteフェス 2016 ▪ and/or/notを合成するクエリー ➔ and条件: mustで指定する(複数指定可能) ➔ or条件: shouldで指定する(複数指定可能)

    ➔ not条件: mustNotで指定する(複数指定可能) ▪ filter条件も設定可能 ➔ and/or/notの前にフィルタ条件を指定する Bool Query PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().bool((must, should, mustNot, filter) -> { must.setProductName_Match("flute"); mustNot.setProductName_Match("gold"); }); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); 52
  33. DBFluteフェス 2016 ▪ スコアを調整するクエリー ➔ functionsにマッチしたものをもとにスコアを変える ➔ queryには通常の検索条件を指定する Function Score

    Query PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().functionScore(query -> { query.setProductCategory_Equal("MusicCD"); }, functions -> { functions.filter(cq -> { cq.setProductName_Match("street"); }, ScoreFunctionBuilders.weightFactorFunction(10.0f)); }, op -> {}); cb.paging(5, 1); }); 53
  34. DBFluteフェス 2016 ▪ 平均値を集計する ➔ Avgのインスタンスが返却される Avg Aggregation 56 PagingResultBean<Product>

    list1 = productBhv.selectPage(cb -> { cb.query().matchAll(); cb.aggregation().setRegularPrice_Avg(); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); EsPagingResultBean<Product> list2 = (EsPagingResultBean<Product>) list1; Aggregations aggregations = list2.getAggregations(); Avg avg = (Avg) aggregations.get("regular_price"); assertEquals(353455.0, avg.getValue());
  35. DBFluteフェス 2016 ▪ フィールドでユニークな項目数を取得する ➔ Cardinalityが返却される Cardinality Aggregation PagingResultBean<Product> list1

    = productBhv.selectPage(cb -> { cb.query().matchAll(); cb.aggregation().setProductCategory_Cardinality(); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); EsPagingResultBean<Product> list2 = (EsPagingResultBean<Product>) list1; Aggregations aggregations = list2.getAggregations(); Cardinality cardinality = (Cardinality) aggregations.get("product_category"); assertEquals(3, cardinality.getValue()); 57
  36. DBFluteフェス 2016 ▪ 様々な統計的数値を得る ➔ ExtendedStatsが返却される ➔ 最大、最小、平均、分散、標準偏差等 Extended Stats

    Aggregation PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().matchAll(); cb.aggregation().setRegularPrice_ExtendedStats(); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); EsPagingResultBean<Product> list2 = (EsPagingResultBean<Product>) list1; Aggregations aggregations = list2.getAggregations(); ExtendedStats extendedStats = (ExtendedStats) aggregations.get("regular_price"); assertEquals(353455.0, extendedStats.getAvg()); 58
  37. DBFluteフェス 2016 ▪ 最大値を取得する ➔ Maxが返却される Max Aggregation PagingResultBean<Product> list1

    = productBhv.selectPage(cb -> { cb.query().matchAll(); cb.aggregation().setRegularPrice_Max(); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); EsPagingResultBean<Product> list2 = (EsPagingResultBean<Product>) list1; Aggregations aggregations = list2.getAggregations(); Max max = (Max) aggregations.get("regular_price"); assertEquals(4000000.0, max.getValue()); 59
  38. DBFluteフェス 2016 ▪ 最小値を取得する ➔ Minが返却される Min Aggregation PagingResultBean<Product> list1

    = productBhv.selectPage(cb -> { cb.query().matchAll(); cb.aggregation().setRegularPrice_Min(); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); EsPagingResultBean<Product> list2 = (EsPagingResultBean<Product>) list1; Aggregations aggregations = list2.getAggregations(); Min min = (Min) aggregations.get("regular_price"); assertEquals(340.0, min.getValue()); 60
  39. DBFluteフェス 2016 ▪ 百分位数を計算する ➔ 小さい順に並べて、X%にある値を取得する ➔ 外れ値を検出するなど ➔ 以下ではRegularPriceの下位1%の位置に347.6

    Percentiles Aggregation PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().matchAll(); cb.aggregation().setRegularPrice_Percentiles(); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); EsPagingResultBean<Product> list2 = (EsPagingResultBean<Product>) list1; Aggregations aggregations = list2.getAggregations(); Percentiles percentiles = (Percentiles) aggregations.get("regular_price"); assertEquals(347.6, percentiles.percentile(1)); 61
  40. DBFluteフェス 2016 ▪ 百分位数における順位を計算する ➔ 指定した値のランクを取得する ➔ 以下ではRegularPriceが1000のときが23.125% Percentile Ranks

    Aggregation PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().matchAll(); cb.aggregation().setRegularPrice_PercentileRanks(op -> op.percentiles(1000, 10000)); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); EsPagingResultBean<Product> list2 = (EsPagingResultBean<Product>) list1; Aggregations aggregations = list2.getAggregations(); PercentileRanks percentileRanks = (PercentileRanks) aggregations.get("regular_price"); assertEquals(23.125, percentileRanks.percent(1000)); 62
  41. DBFluteフェス 2016 ▪ 基本的な統計的数値を算出する ➔ Statsが返却される ➔ 項目数、最小値、最大値、平均値、合計値 Stats Aggregation

    PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().matchAll(); cb.aggregation().setRegularPrice_Stats(); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); EsPagingResultBean<Product> list2 = (EsPagingResultBean<Product>) list1; Aggregations aggregations = list2.getAggregations(); Stats stats = (Stats) aggregations.get("regular_price"); assertEquals(353455.0, stats.getAvg()); 63
  42. DBFluteフェス 2016 ▪ 合計値を取得する ➔ Sumが返却される Sum Aggregation PagingResultBean<Product> list1

    = productBhv.selectPage(cb -> { cb.query().matchAll(); cb.aggregation().setRegularPrice_Sum(); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); EsPagingResultBean<Product> list2 = (EsPagingResultBean<Product>) list1; Aggregations aggregations = list2.getAggregations(); Sum sum = (Sum) aggregations.get("regular_price"); assertEquals(7069100.0, sum.getValue()); 64
  43. DBFluteフェス 2016 ▪ フィールドに値を持つ件数を取得する ➔ ValueCountが返却される ➔ スクリプトによる指定も可能 Value Count

    Aggregation PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().matchAll(); cb.aggregation().setProductCategory_Count(); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); EsPagingResultBean<Product> list2 = (EsPagingResultBean<Product>) list1; Aggregations aggregations = list2.getAggregations(); ValueCount valueCount = (ValueCount) aggregations.get("product_category"); assertEquals(20, valueCount.getValue()); 65
  44. DBFluteフェス 2016 ▪ 指定したフィルタで項目を絞り込む ➔ 子のAggregationをフィルタするときに利用 ▪ ➔ ➔ Filter

    Aggregation PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().matchAll(); cb.aggregation().filter("filter", cq -> cq.setProductName_Equal("flute"), op -> {}, aggs -> aggs.setRegularPrice_Avg()); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); EsPagingResultBean<Product> list2 = (EsPagingResultBean<Product>) list1; Aggregations aggregations = list2.getAggregations(); Filter filter = (Filter) aggregations.get("filter"); Avg avg = (Avg) filter.getAggregations().get("regular_price"); assertEquals(1516666.6666666667, avg.getValue()); 66
  45. DBFluteフェス 2016 ▪ ヒストグラムを生成する ➔ Histogramが返却される Histogram Aggregation PagingResultBean<Product> list1

    = productBhv.selectPage(cb -> { cb.query().setRegularPrice_LessThan(2000); cb.aggregation().setRegularPrice_Histogram(op -> { op.interval(200).extendedBounds(0L, 2000L); }, aggs -> {}); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); EsPagingResultBean<Product> list2 = (EsPagingResultBean<Product>) list1; Aggregations aggregations = list2.getAggregations(); Histogram histogram = (Histogram) aggregations.get("regular_price"); assertEquals(11, histogram.getBuckets().size()); assertEquals(3L, histogram.getBuckets().get(1).getDocCount()); 67
  46. DBFluteフェス 2016 ▪ フィールドに値が存在しない項目を得る ➔ Missingが返却される Missing Aggregation PagingResultBean<Product> list1

    = productBhv.selectPage(cb -> { cb.query().matchAll(); cb.aggregation().setRegularPrice_Missing(); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); EsPagingResultBean<Product> list2 = (EsPagingResultBean<Product>) list1; Aggregations aggregations = list2.getAggregations(); Missing missing = (Missing) aggregations.get("regular_price"); assertEquals(0, missing.getDocCount()); 68
  47. DBFluteフェス 2016 ▪ フィールド値が範囲内にある件数を取得する ➔ Rangeが返却される Range Aggregation PagingResultBean<Product> list1

    = productBhv.selectPage(cb -> { cb.query().matchAll(); cb.aggregation().setRegularPrice_Range(op -> { op.addUnboundedFrom("all", 0) .addRange("average", 1000, 5000) .addUnboundedTo("cheap", 1000); }, aggs -> {}); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); EsPagingResultBean<Product> list2 = (EsPagingResultBean<Product>) list1; Aggregations aggregations = list2.getAggregations(); Range range = (Range) aggregations.get("regular_price"); assertEquals(4, range.getBuckets().get(0).getDocCount()); 69
  48. DBFluteフェス 2016 ▪ 指定した単語が含まれる件数を取得する ➔ Termsが返却される ➔ 含まれる単語と件数が取得できる Terms Aggregation

    PagingResultBean<Product> list1 = productBhv.selectPage(cb -> { cb.query().matchAll(); cb.aggregation().setProductName_Terms(); cb.query().addOrderBy_ProductHandleCode_Asc(); cb.paging(5, 1); }); EsPagingResultBean<Product> list2 = (EsPagingResultBean<Product>) list1; Aggregations aggregations = list2.getAggregations(); Terms terms = (Terms) aggregations.get("product_name"); List<Bucket> buckets = terms.getBuckets(); assertEquals("100g", buckets.get(0).getKey()); assertEquals(4, buckets.get(0).getDocCount()); 70
  49. DBFluteフェス 2016 ▪ Elasticsearch 5.0対応 ▪ geo_point対応 ▪ ネストしたプロパティへの対応 ▪

    multifieldの対応 ▪ join対応 ▪ HTTPでの接続方法 ▪ 適切でない利用方法やクエリを通知する 今後のタスク 71