2023-12-07

ElasticsearchのSearch APIで使えるクエリを覚える

この記事は Elastic Stack (Elasticsearch) Advent Calendar 2023 Advent Calendar 2023 7日目の記事です。 Elastic Stack (Elasticsearch) Advent Calendar 2023のカレンダー | Advent Calendar 2023 - QiitaElastic Stack (Elasticsearch) Advent Calendar 2023のカレンダーページです。https://qiita.com/advent-calendar/2023/elasticsearch

そろそろ Elasticsearch をちゃんと理解しないといけなそうなので、クエリについてまとめておきます。 使っているバージョンは 8.11.1 です。

まず

この記事を試したい方は以下から Clone してください。 GitHub - righ/elastic-tryContribute to righ/elastic-try development by creating an account on GitHub.https://github.com/righ/elastic-try

必要なものは docker(compose), curl で、jq, make もあるとなおよいです。

docker compose up make data # makeがない場合は Makefileのコマンドを貼ってください。

としたら準備完了です。

params ディレクトリにパラメータが入っているので、 以下のように search API を実行します。

cd elastic-try ./search.sh params/match.yaml
note
  • 生成データは Faker によって自動生成したものです。
  • すべてダミーのデータであり、特定の個人を指す情報は含まれていません。仮にあなたの本名が含まれていてもそれはただの偶然です。
  • ソースコードはこちら

Elasticsearchは HTTP REST API をインターフェースとして提供しています。 SDKは基本的にREST APIへのアクセスをラップしたものなので API を理解できれば実装もきっとなんとかなります。

この記事では特定の言語に依存せずに、curlを使い REST API で検証しています。

curl -u 'user:password' -X GET "http://localhost:9200/my-index-000001/_search?pretty"
memo
  • 認証情報はBasic認証で指定します。
    • -u オプションで指定しても良いし、 user:password@localhost のように指定しても構いません。
    • 認証は Basic認証以外にも JWT 等もできるらしいです。興味のある方はこちらからどうぞ。
  • ?pretty パラメータを指定することで返却されるJSONが整形されるので、curl経由の場合は基本的につける方針で良いでしょう。

検索APIのパスは /<target>/_search/_search です。 基本的にHTTPメソッドは POST ですが、クエリを指定しない場合は GET でも構いません。

<target> にはインデックスかエイリアスを指定します。次のようなパターンがあります。

  • 単一: /target_index/_search
  • 複数: /target_index1,target_index2/_search
  • ワイルドカード: /target_index*/_search
  • すべて: /_all/_search/_search

クエリのボディには 検索に必要な情報をJSON形式で指定します。 JSONトップレベルに指定可能な主要なキーは以下があります。

query
  • 検索条件を指定します。このあとのセクションで解説します。
size
  • 返される結果の数。
from
  • 返される結果の開始位置。
aggs
sort
  • 結果のソート方法。
search_after

Query

クエリの構文にはQuery DSL と SQL DSL があります。

この記事ではQuery DSLについて解説します。

SQL DSL

Query DSL

まず、 {"query": {}} のようにたくさんのオブジェクトを書いていくわけですが、 このオブジェクトは階層によって指定できるキーが異なります。

query キーにはクエリオブジェクトを指定するわけですが、クエリオブジェクトに指定できるキーは1つだけです。当然0個でもダメですし2個以上でもダメです。 そのため複数の検索条件がある場合は一つにまとめる必要があります。 ここでいう一つ一つの検索条件はLeaf Queryといい、複数のLeaf Queryをまとめるのが Compound Queryです。

ここからは代表的なクエリを見ていきます。

Leaf Query

match_all

match_allクエリは、すべてのドキュメントを返します。 これは、インデックス内の全ドキュメントを取得する際に使用される最も単純なクエリです。

  • ./search.sh params/match_all.yaml | jq '.hits.hits[] | {id: ._id, birthdate: ._source.birthdate}' + curl --data-binary @params/match_all.yaml -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 6078 0 5958 100 120 566k 11686 --:--:-- --:--:-- --:--:-- 847k { "id": "86688883-0084-4fda-bd6f-6de32236cfaa", "birthdate": "2023-11-03" } { "id": "a3fcc8a6-18ce-4f5e-a9c5-a20e5405b2ef", "birthdate": "2023-07-02" } { "id": "4810a69b-316f-4d69-bdeb-881700c3838f", "birthdate": "2023-05-24" }

また、逆に何も返却しないクエリ match_none もあります。

  • ./search.sh params/match_none.yaml + curl --data-binary @params/match_none.yaml -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' { "took" : 1, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 0, "relation" : "eq" }, "max_score" : null, "hits" : [ ] } }

いずれも検索条件を指定しないため、主にトップレベルのクエリに指定します。

Match all query | Elasticsearch Guide [8.11] | Elastichttps://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-all-query.html

match

matchクエリは、指定されたフィールドに対して全文検索を行います。 特定のフィールドに特定のテキストが含まれているドキュメントを検索することができます。

以下は「ダイヤモンド キャビネット バーゲン」をすべて含むドキュメントです。

  • ./search.sh params/match.yaml | jq '.hits.hits[] | {id: ._id, _score, note: ._source.note}' + curl --data-binary @params/match.yaml -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 6007 0 5845 100 162 666k 18918 --:--:-- --:--:-- --:--:-- 1173k { "id": "8d9068f0-6d09-4a0b-87b0-2464bcf7e3a5", "_score": 7.11467, "note": "敵対的な助けて見出し憲法彼女。鉱山バスケットスキーム省略葉キャビネット。\n行進キャビネット革新ジャム分割。軸建築サラダコピー。\n倫理脊椎助けて葉索引必要。敵対的な中央雪通行料金織る擁する。合計隠す協力ヒット索引。\n人形ダイヤモンドトレーナー明らかにする省略〜。電話フレームコーラス特徴ダイヤモンド。副持っていました編組。動物反射状況移動。\nバーゲン癌催眠術。" } { "id": "c9327cac-0376-4659-b157-487629b11f81", "_score": 6.8270493, "note": "トリビュートリハビリマリン出演者フレーム。トスブランチ血まみれのリニア。ダイヤモンド状況呼ぶ差別する敵。\nブラケット職人鉱山人形人形シュガー。野球状況偏差。参加するインチ血まみれの〜試してみる尿。文言スキーム暖かいジャムオークション。\nバーゲン暖かい楽しんで彼キャビネット。副厳しい大統領午前風景編組供給。" } { "id": "bcb2a3ef-bdd4-459f-9338-5275d5172e38", "_score": 5.914349, "note": "立派なダイヤモンド運指名連続。デッドストレージ文言不自然なニュース。\n追放する電池衝突追放する怒りクロス。販売転倒差別する品質持つ。\nじぶんの持ってる明らかにする職人。感謝する憲法革新暖かい〜サラダ。\nキャビンバナーチーズパーセントあなた自身。コンペ極端な状況保持するクール。器官トーン憲法建築。\n織るパン中央教会リフト改善職人。花嫁ヒール尊敬するバーゲン持っていましたキャビネット。" }

matchで指定されたクエリはトークンに分割されて検索されます。 複数に分割された場合に、それがどのように評価されるかを operator パラメータで指定できます。 デフォルトでは OR が使用されますが、AND を指定すると、すべての語句がドキュメント内に存在することを期待します。

Match query | Elasticsearch Guide [8.11] | Elastichttps://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html

multi_match

複数のフィールドに対して全文検索を行うものに multi_match 検索があります。

match では直下のキーにフィールドを指定しましたが、 multi_match では fields キーに指定します。

以下は「ダイヤモンド タワー」の両方を note あるいは favorites に含まれるドキュメントを抽出する例です。

  • ./search.sh params/multi_match.yaml | jq '.hits.hits[] | {id: ._id, _score, favorites: ._source.favorites, note: ._source.note}' + curl --data-binary @params/multi_match.yaml -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 7616 0 7441 100 175 1107k 26672 --:--:-- --:--:-- --:--:-- 2479k { "id": "72830bda-fdd8-40bc-8ec2-05399c4310ea", "_score": 4.9730825, "favorites": [ "腐った", "彼女", "尊敬する" ], "note": "暖かいリンク残るリフト本質的な必要。大統領ホイール証言する差別する催眠術。立派な画面バスケット尊敬するタワー。\n保証金ダイヤモンド腐ったクールそれ。意図ない叔父狐コンペ文言。行進あなた自身コミュニケーション錯覚トーン。\nスペル緩む残るクルー。柔らかい証言する怒りパイオニア合計索引。プラスチック試してみるタワー花嫁トースト。" } { "id": "60123571-97a0-4736-aae1-d47bdc592ae4", "_score": 4.8447113, "favorites": [ "感謝する", "障害", "助けて" ], "note": "ノートカレッジ持ってる教授索引索引タワー。リンク出演者助けてそれ評議会虐待君は奨励します。\nコーラス憲法彼女クール。コーラス叔父タワー主婦連続隠す再現する。\nはフェミニスト軸ボトル。画面フレーム花嫁。私見出しヘア鉱山試してみるコンペ省略。\n移動擁する電話残るはブレーキ拡張バス。職人移動バナー助けて。\nバナーピックリンク連続敵緩む。〜文言ダイヤモンド。" } { "id": "f4322487-f12a-4d3e-9c1c-3efc4c9d9a95", "_score": 4.5710826, "favorites": [ "舗装", "建築", "隠す" ], "note": "バスインチサンプル偏差。保証金ブラケットプラスチックダイヤモンド敵リハビリ。タワー緩むバケツ。\nオークション自体残る溝分割持ってる呼ぶ。差別するリハビリ陶器協力倫理隠す。戦略的軸学生陶器。\n敵出演者緩む建築マリン怒り催眠術。移動キャビネット見出し自体。リニア倫理トーン持ってるダイヤモンド。" } { "id": "82033745-d07f-444c-b1b3-42bd1657c2da", "_score": 4.491337, "favorites": [ "必要", "呼ぶ", "ダイヤモンド" ], "note": "尊敬する指名タワー動物ダイヤモンド。スキームテント残る風景錯覚トースト。呼ぶノートプラスチック拡張。\n意図改善あなた自身画面あった特徴。\n織るコミュニティジャムバケツ立派なバス。\n葉販売中世主人。ピックじぶんの織る文言。\n尿主人テントプラスチックキャビン。同行戦略的賞賛する知覚ソース。コピーフレームタワー隠す。" }

Multi-match query | Elasticsearch Guide [8.11] | Elastichttps://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html

match_phrase

前述のように指定したクエリ文字列はトークンに分割されて検索されます。 そのため、検索に指定した文字列の単語がバラバラに入っていたり前後している文章にもヒットするのですが、それでは都合が悪い場合もあります。

match_phraseでは指定した文字列がそのまま含まれる文章にのみヒットします。 Google検索で言えばダブルクォートで囲んだ検索("クエリ")みたいなもんですね。SQLで言えば LIKE "%クエリ%" みたいな。

今回は複合されたワードを検索してみました。なんでこんなのが4件もヒットするんだよ。

  • ./search.sh params/match_phrase.yaml | jq '.hits.hits[] | {id: ._id, _score, note: ._source.note}' + curl --data-binary @params/match_phrase.yaml -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 7821 0 7735 100 86 1082k 12326 --:--:-- --:--:-- --:--:-- 1909k { "id": "33ca30b5-a15c-4dfb-830e-bf7e6e1eb38a", "_score": 6.0973763, "note": "ログ錯覚ブラケット。コピー雪助けて鉱山コピーコーナーフレーム。\nリハビリ彼日曜日ない普通の管理する改善暖かい。サラダブレーキキャビン腐った日曜日連続衝突。\nリニア花嫁舗装リンクオークションホイール高い。協力舗装トレーナーバス。電話シュガーソースダイヤモンド。\nベルベット主婦敵シュガー血まみれのコーナー省略障害。出演者ダッシュ動物バーゲン。" } { "id": "1f426815-d714-42b6-a599-6fa119d9dc99", "_score": 5.5196123, "note": "マリン文言電話ハードウェア屋根裏見落とすカラム厳しい。発生する画面今血まみれの行進指名建築運。学生狐彼女賞賛する軸出演者ダッシュ。\n同行通行料金ベルベットハンマー。厳しいコンペ必要ヒール。\n擁するバスケット極端な倫理ノート怒り偏差。錯覚革新部隊クール極端な軸サワー擁する。ないホイールバスリフト。シェービング品質指名感謝する日曜日。" } { "id": "bf2fe9c9-245f-4a12-a2bc-6ed7ae9673cd", "_score": 5.1916523, "note": "癌明らかにする葉腐った。スキーム本質的な障害本質的な。倫理品質持ってるトス。\n月賞賛する賞賛する中央ハードウェア文言器官ブラケット。ブラケット欠乏尊敬するパイオニア。改善特徴参加する出演者ダッシュ。\nバナー野球再現するプラスチック目的建築自体。本質的な普通のコーラス。ささやき敵対的なインチフレーム残る敵タワー。\n楽しんでリニア必要立派なクロス。あなた自身編組それパイオニア意図。" } { "id": "a8f28082-ad57-4a40-a79b-0c8ce625a58f", "_score": 5.1916523, "note": "叔父トレーナーバナーテントタワー風景近代化する。感謝する分割参加する狐パイオニア。\n戦略的緩む自体出演者ダッシュ。衝突索引カレッジ評議会自体埋め込む助けて。\n品質風景バスソース学生。拡張尿あなた自身舗装。\nソース主婦供給主婦証言する文言。持ってる省略指名電池。ストレージコーラス目的トーン君はささやき。\n仕上げクール画面じぶんのプラスチック。販売溝建築教会暖かいサンプル。" }

Match phrase query | Elasticsearch Guide [8.11] | Elastichttps://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query-phrase.html

term

termクエリは、特定のフィールドが正確な値を持つドキュメントを見つけるために使用されます。 例えば、"status": "active"のように、フィールドが指定された正確な値を持つドキュメントを検索します。

term検索を行う場合、mappingのtypeが keyword になっている必要があります。

血液型が AB- のドキュメントを抽出する例です。

  • ./search.sh params/term.yaml | jq '.hits.hits[] | {id: ._id, _score, blood_group: ._source.blood_group}' + curl --data-binary @params/term.yaml -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 9295 0 9180 100 115 1032k 13244 --:--:-- --:--:-- --:--:-- 1815k { "id": "15fcc7a7-fab8-4cd8-9a78-a410b0550b2e", "_score": 2.1508634, "blood_group": "AB-" } { "id": "190cf809-60da-4d4f-828b-2bbd818b3d24", "_score": 2.1508634, "blood_group": "AB-" } { "id": "4df36921-bbce-4e1f-9e55-910773a3223e", "_score": 2.1508634, "blood_group": "AB-" } { "id": "8159715d-8cca-4f67-8372-82a58b34177e", "_score": 2.1508634, "blood_group": "AB-" } { "id": "a0c8fcca-59ef-4afd-a887-f8053198dcc6", "_score": 2.1508634, "blood_group": "AB-" }

Term query | Elasticsearch Guide [8.11] | Elastichttps://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html

terms

termの複数バージョンに termsクエリがあります。SQLでいうとIN句のようなものですね。 termと同じく keyword タイプでなければいけません。

血液型が AB-O+ のドキュメントを抽出する例です。

  • ./search.sh params/terms.yaml | jq '.hits.hits[] | {id: ._id, blood_group: ._source.blood_group}' + curl --data-binary @params/terms.yaml -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 9874 0 9737 100 137 968k 13961 --:--:-- --:--:-- --:--:-- 1607k { "id": "c1181423-4e8c-4a51-817e-a81f8141e1e4", "blood_group": "AB-" } { "id": "00b562f5-7fdf-43f5-865e-fa61194ff6dd", "blood_group": "O+" } { "id": "d15e2e2c-da1c-4c68-864d-1dc5c18cb6fc", "blood_group": "AB-" } { "id": "64ce9862-188f-4fbf-b49c-6cfbff99c207", "blood_group": "AB-" } { "id": "9b70612a-5ef4-4fe7-967c-551a3c7305ef", "blood_group": "AB-" }

Terms query | Elasticsearch Guide [8.11] | Elastichttps://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-terms-query.html

range

rangeクエリは、数値、日付、文字列などの範囲を指定して検索を行います。 lt, lte, gt, gte の不等号を用いて範囲を制限します。下限、上限どちらかだけでも構いません。

  • ./search.sh params/range.yaml | jq '.hits.hits[] | {id: ._id, _score, saving: ._source.saving}' + curl --data-binary @params/range.yaml -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 5890 0 5752 100 138 724k 17811 --:--:-- --:--:-- --:--:-- 1437k { "id": "c32bf15b-8c6e-415d-9a79-d079484a22bd", "_score": 1.0, "saving": 2645 } { "id": "6bc1a232-5269-41f3-9498-33a09fcb330a", "_score": 1.0, "saving": 6467 } { "id": "b07ace86-c3ae-400a-a3d0-d1ce2db84eaa", "_score": 1.0, "saving": 6269 }

また、Date型の場合はDateMath フォーマットを使うことで現在を起点とした相対的な日時を表現できます。 例えば now-1h/d は現在より1時間前の日時を日付単位(00:00:00)に丸めます。詳しくはリンクを参照してください。

直近一ヶ月に登録したユーザを抽出する例です。

  • ./search.sh params/range_timestamp.yaml | jq '.hits.hits[] | {_score, created_at: ._source.created_at}' + curl --data-binary @params/range_timestamp.yaml -H 'Content-Type: application/yaml' -H 'Accept: application/json' -X POST 'http://localhost:9200/profile1/_search?pretty' % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 9382 0 9320 100 62 816k 5560 --:--:-- --:--:-- --:--:-- 1308k { "_score": 1.0, "created_at": "2023-11-28T13:33:49.523134" } { "_score": 1.0, "created_at": "2023-11-22T02:05:08.058646" } { "_score": 1.0, "created_at": "2023-11-24T08:01:24.688100" } { "_score": 1.0, "created_at": "2023-11-19T08:20:35.068986" } { "_score": 1.0, "created_at": "2023-11-29T22:54:08.064831" }
warning
  • ちなみに m は分で、 M は月です。
  • あと現在時刻を基点としているため、上記を実行してもタイミングによって結果が異なります。

Range query | Elasticsearch Guide [8.11] | Elastichttps://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html

Compound Query

bool

複雑な条件をツリー構造のようにつなげることで、一つにまとめるのがこのBool Queryです。 大抵、検索条件は複数になるので bool はよく使われます。

boolクエリではmust、should、must_not、filterを使用して、AND、OR、NOTの論理演算を実現します。

must
  • 条件を満たすドキュメントを検索します(AND)。
should
  • 条件のいずれかを満たすドキュメントを検索します(OR)。
must_not
  • 指定された条件を満たさないドキュメントを検索します(NOT)。
filter
  • クエリの結果を特定の条件でフィルタリングしますが、スコアリングには影響しません。
  • filter内では Leaf Queryで指定したboost パラメータは無視されます。

せっかくなので must を filterに変えた場合にスコアが変化する様子を見ておきましょう。

must
    • ./search.sh params/bool_must.yaml | jq '.hits.hits[] | {id: ._id, _score}' + curl -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' --data-binary @params/bool_must.yaml % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 9683 0 9360 100 323 817k 28875 --:--:-- --:--:-- --:--:-- 1182k { "id": "42caaf3a-f12b-45ac-9145-775e6d5383af", "_score": 4.60024 } { "id": "d9fd311e-f4a6-4cac-9a18-a7b8546a2c17", "_score": 4.379561 } { "id": "b85b9551-4850-42c7-8f44-31faacb4f45f", "_score": 4.3150063 } { "id": "3fe6ee05-a243-43b9-8592-8409fdeca688", "_score": 3.8261707 } { "id": "9c4eaeeb-d251-49ee-9b4d-3af2b709423f", "_score": 3.8245466 }
filter
    • ./search.sh params/bool_filter.yaml | jq '.hits.hits[] | {id: ._id, _score}' + curl -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' --data-binary @params/bool_filter.yaml % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 9776 0 9451 100 325 1894k 66721 --:--:-- --:--:-- --:--:-- 4773k { "id": "0db51d22-5c68-44eb-8b35-3f36513e1e39", "_score": 0.0 } { "id": "325ccfd9-5a19-4415-b0f3-eb4e56796a11", "_score": 0.0 } { "id": "63ab2ac6-9cd3-4e74-90a0-b7e196e6b544", "_score": 0.0 } { "id": "9c4eaeeb-d251-49ee-9b4d-3af2b709423f", "_score": 0.0 } { "id": "16e414df-81a8-4f2e-b163-dc2ce4cdb602", "_score": 0.0 }

filterの方はスコアが全部ゼロになっていますね。

Boolean query | Elasticsearch Guide [8.11] | Elastichttps://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html

boosting

特定ドキュメントのスコアを「下げる」ことに焦点を当てたクエリです。

検索結果の品質を向上させるために、あるドキュメントを他のドキュメントよりも低い優先順位にするのに使われます。

パラメータは以下の3つです。

positive
  • 検索結果に含めたいドキュメントの条件を指定する。
  • スコアを下げたいドキュメントにも一致させる必要があります。
  • スコアを上げる効果はありません。パラメータ名分かりにくくない?
negative
  • 通常は結果に含まれるが、重要度を下げたいドキュメントの条件を指定します。
negative_boost
  • negative条件に一致したドキュメントのスコアに適用する乗数です。

以下は血液型が A+, A-のいずれかに一致し、A-のときはスコアを下げる例です。

  • ./search.sh params/boosting.yaml | jq '.hits.hits[] | {_score, blood_group: ._source.blood_group}' + curl --data-binary @params/boosting.yaml -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 19909 0 19556 100 353 1733k 32035 --:--:-- --:--:-- --:--:-- 2777k { "_score": 1.0, "blood_group": "A+" } { "_score": 1.0, "blood_group": "A+" } { "_score": 1.0, "blood_group": "A+" } { "_score": 0.3, "blood_group": "A-" } { "_score": 0.3, "blood_group": "A-" } { "_score": 1.0, "blood_group": "A+" } { "_score": 1.0, "blood_group": "A+" } { "_score": 0.3, "blood_group": "A-" } { "_score": 1.0, "blood_group": "A+" } { "_score": 0.3, "blood_group": "A-" }

Boosting query | Elasticsearch Guide [8.11] | Elastichttps://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-boosting-query.html

constant_score

一致する条件に固定のスコアを設定するクエリです。 filter にはクエリ、boost には設定したいスコアを指定します。

以下は 「ダイヤモンド」「ダニ」を含むドキュメントに 123 のスコアを設定する例です。

  • ./search.sh params/constant_score.yaml | jq '.hits.hits[] | {_score, note: ._source.note}' + curl --data-binary @params/constant_score.yaml -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 6158 0 5908 100 250 931k 40348 --:--:-- --:--:-- --:--:-- 2004k { "_score": 123.0, "note": "連続舗装ダニ癌ノート持つ。狭い管理する改善舗装コーナー教会クロス。ジャーナル装置管理するサラダ電話指名奨励します。\n大統領不自然な式差別するノートバナー持ってるダイヤモンド。タワーバス証言するダイヤモンド軸午前感謝する。リフト自体自体証言する意図私。\n奨励します狐スキームパーセント。じぶんのコーラスコミュニケーション狭い。\nプラスチックパーセント同行装置憲法カレッジ。教会葉発生する。" } { "_score": 123.0, "note": "ヘア残るダニ虐待楽しんで。残る教授怒り癌隠すコミュニケーション主婦。\n倫理出演者副。感謝するフレーム改善雪行進風景。脊椎〜ブランチパイオニア暖かい。\n保持するダイヤモンド省略。ログサワー編組チーズ。ハードウェアダニ細かい衝突戦略的狭い。\n保証金連続鉱山。オークションノート部隊極端なパン血まみれの差別するリフト。" } { "_score": 123.0, "note": "アクセルペダルコーラス花嫁極端な敵対的なコピー。日曜日同行葉私。\nスマッシュバスケット織る。符号デフォルト教授ダイヤモンド屋根裏索引尊敬する拡張。差別する自体暖かいマリン。\nタワー人形ダニ分割。花嫁陶器腐った。プラスチック私保証金。\n販売フェミニスト再現するハードウェア改善〜評議会。探査建築助けてシュガー。" }

これは簡単ですね。

memo
  • 条件句のキーが query でなくて filter なのは該当条件をスコアに加算しないことを暗示しているのではないかと 推測しています。これは裏取りしていないので間違っていたら教えてください。

dis_max

複数の条件を指定し、それらの条件にマッチするレコードを返却します。

スコアはマッチした条件の合計となりますが、最大スコアの条件以外は tie_breaker に指定した値を乗じます。 tie_breaker の値は 0 から 1 で、デフォルトは 0 です。つまり2番以降のスコアを減衰させることが目的です。

以下は 1, 10, 100 のスコアを serial_number: 1, 2, 3 に条件づけながら当てています。

文章だとわかりにくいのでこのテーブルを見てください。

ID: 1ID: 2ID: 3
Score: 11 * 0.8 = 0.81 * 0.8 = 0.81 * 0.8 = 0.8
Score: 1010 * 0.8 = 810
Score: 100100100
合計108.810.8100.8

一番高いスコアはそのまま加算され、 それ以外のスコアは tie_breaker=0.8 が乗じられてから加算されます。

  • ./search.sh params/dis_max.yaml | jq '.hits.hits[] | {_score, serial_number: ._source.serial_number}' + curl --data-binary @params/dis_max.yaml -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 6592 0 5859 100 733 1188k 148k --:--:-- --:--:-- --:--:-- 3218k { "_score": 108.8, "serial_number": 1 } { "_score": 100.8, "serial_number": 3 } { "_score": 10.8, "serial_number": 2 }

Disjunction max query | Elasticsearch Guide [8.11] | Elastichttps://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-dis-max-query.html

function_score

elasticsearchは自動的にマッチした内容によりスコアの計算を行い、 ソートや足切りにスコアが用いられるためこの調整はとても重要です。

で、function_score はスコアを調整するためのクエリなんですが、柔軟な分、複雑とも言えます。

重要なパラメータは以下です。

query
  • 検索条件です。スコアを設定したいドキュメントにマッチするように条件指定します。
boost
  • 条件にマッチしたドキュメントのスコアに設定される乗数です。
score_mode
  • functions にはスコア設定を複数指定します。
  • これらをどのように集約するかの方法(関数)が score_mode です。
boost_mode
  • function_score以外に、クエリに該当したドキュメントにもスコアが設定されています。
  • そのスコアとfunctionsのスコアを集約する方法(関数)が boost_mode です。
functions
  • マッチしたドキュメントに対してどのようにスコアを設定するかの方法を複数指定します。

スコアはこんな感じに評価されます。

boost_mode( queryのスコア, score_mode(functionを評価したスコア...) ) * boost

肝心のスコアの調整方法は script_score, weight, random_score, field_value_factor, decay functions があります。以下で簡単に解説していきます。

script_score

スコアの計算をPainlessというスクリプト言語で記述します。

何も思い浮かばなかったので、男性を対象として現在位置を絶対値にして足したものをスコアにしてみました。

  • ./search.sh params/function_score_script_score.yaml | jq '.hits.hits[] | {id: ._id, _score, location: ._source.current_location}' + curl --data-binary @params/function_score_script_score.yaml -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 19258 0 18816 100 442 1974k 47486 --:--:-- --:--:-- --:--:-- 3134k { "id": "153c651c-8221-4ba7-948e-1a0b05861a98", "_score": 266.30508, "location": [ -86.389169, -179.915905 ] } { "id": "f0b4d2f7-9d04-4089-a293-5913bf86d5df", "_score": 262.76364, "location": [ 84.5211685, 178.242455 ] } { "id": "37efb287-75c1-4bba-b953-873dac7a6680", "_score": 257.74243, "location": [ -84.8737965, 172.868636 ] } { "id": "38463ea0-6b09-4a80-aa2e-ef1e214bb36f", "_score": 256.9796, "location": [ 88.728002, 168.25162 ] } { "id": "62c7aa50-4300-445c-8aff-a12585ba5973", "_score": 255.51001, "location": [ -77.401129, -178.10887 ] } { "id": "af910ee5-fe58-40d0-8971-cf3dfa2f1651", "_score": 254.89796, "location": [ -88.1911165, 166.70685 ] } { "id": "dbe9d7f2-5b89-481c-a6f0-1e524744ecc4", "_score": 252.6018, "location": [ 87.281143, 165.320665 ] } { "id": "9db4f87c-0799-4561-a86e-7de704cac098", "_score": 252.0036, "location": [ -82.607441, -169.396153 ] } { "id": "bee7ab49-67f9-4951-aaf6-aaa9b875a939", "_score": 250.59, "location": [ 71.90346, -178.686535 ] } { "id": "b90b3f85-b79a-4512-9cbe-80b645b732e4", "_score": 250.35226, "location": [ -70.7489415, 179.603316 ] }

boost_mode がデフォルトで multiply になっているため filterのスコアが0で、最終的なスコアが0になってしまいます。これを避けるために boost_mode で max (大きい方が採用される)を選択しました。

weight

該当したドキュメントのスコアにつける重み(乗数)です。 基本的にはfilterして該当したドキュメントに設定するのが一般的です。

以下は東京に住んでいる女性で、血液型がA-なら10,A+なら15,AB+なら20の重みをつける例です。献血か?

  • ./search.sh params/function_score_weight.yaml | jq '.hits.hits[] | {id: ._id, _score, sex: ._source.sex, blood_type: ._source.blood_group, residence: ._source.residence}' + curl -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' --data-binary @params/function_score_weight.yaml % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 10576 0 9577 100 999 1082k 112k --:--:-- --:--:-- --:--:-- 2065k { "id": "37bb75a0-2d52-4262-8913-a4dc51922098", "_score": 171.35684, "sex": "F", "blood_type": "AB+", "residence": "東京都国分寺市麹町39丁目25番6号" } { "id": "1db4e165-5c53-4be9-ae87-7f9b9d427225", "_score": 158.68289, "sex": "F", "blood_type": "AB+", "residence": "東京都清瀬市羽折町17丁目17番17号 方京シティ654" } { "id": "46b19867-815a-4a98-b4b1-0432e7edb9c3", "_score": 153.08215, "sex": "F", "blood_type": "AB+", "residence": "東京都大田区百村5丁目22番14号 柿木沢新田シャルム255" } { "id": "0ffd3fb6-c28a-44db-89b4-523990c24ca0", "_score": 121.241974, "sex": "F", "blood_type": "A+", "residence": "東京都目黒区白金14丁目8番7号 シティ松石330" } { "id": "d6345db4-b114-48d7-afa3-79969d91815f", "_score": 112.831024, "sex": "F", "blood_type": "A+", "residence": "東京都川崎市中原区箪笥町25丁目18番19号 コート細野538" }
random_score

0~1までのランダムな数値を生成します。

そのままですね。

  • ./search.sh params/function_score_random_score.yaml | jq '.hits.hits[] | {id: ._id, _score}' + curl --data-binary @params/function_score_random_score.yaml -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 9541 0 9432 100 109 1269k 15026 --:--:-- --:--:-- --:--:-- 2329k { "id": "d79100bc-70c3-4395-a52c-c358577ae1fe", "_score": 997.94995 } { "id": "da0bfbfc-498a-4453-8156-09f41d3a5c03", "_score": 997.4083 } { "id": "46b19867-815a-4a98-b4b1-0432e7edb9c3", "_score": 997.4039 } { "id": "921f3d9f-437f-464b-9be0-b641c7687bec", "_score": 995.68024 } { "id": "5ddb6eaa-a912-4d5c-849b-2ce66dcdbe1f", "_score": 994.4161 }

この例では特にすることがなかったので最終的にヒットしたスコアに対して boost の値を乗じています。

field_value_factor

ドキュメントのフィールドを使ってスコアに影響を与えられます。

これは script_score 関数と似ていますが、スクリプトのオーバーヘッドを避けられることがその強みです。 配列のような多値フィールドに使用した場合は、そのフィールドの最初の値のみが計算に使用されます。

パラメータは以下。

field
  • 対象フィールド。
factor
  • 抽出した値にかける乗数。
modifier
  • 抽出した値に適用する関数。デフォルトは何もしない。
  • 対数、累乗、累乗根などがある。
missing
  • フィールドがない場合に補完する値

今回の例では貯金額(saving)が大きいほどスコアが大きくなるようにしました。 データの分散が大きいため自然対数を取ることにします。

  • ./search.sh params/function_score_field_value_factor.yaml | jq '.hits.hits[] | {id: ._id, _score, saving: ._source.saving}' + curl -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' --data-binary @params/function_score_field_value_factor.yaml % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 9865 0 9665 100 200 1280k 27133 --:--:-- --:--:-- --:--:-- 2408k { "id": "14313ebc-e101-40ed-bec4-bacf3763daa4", "_score": 21.412218, "saving": 995813333 } { "id": "82b7c85f-a05a-467b-a87f-6f91265c02f8", "_score": 21.408371, "saving": 991991116 } { "id": "c1181423-4e8c-4a51-817e-a81f8141e1e4", "_score": 21.373821, "saving": 958302711 } { "id": "54e519d8-17da-4cba-ab5d-1a73c1b6883b", "_score": 21.36713, "saving": 951911721 } { "id": "00b562f5-7fdf-43f5-865e-fa61194ff6dd", "_score": 21.364464, "saving": 949377196 }
note
  • 一部に0を含むデータがあるので、1を加えてから自然対数を取る ln1p を使いました。
  • 0を対象に ln を使うとこんなエラーが出ます
    • field value function must not produce negative scores, but got: [-Infinity] for field value: [0.0]; consider using ln1p or ln2p instead of ln to avoid negative scores
decay_functions

減衰関数を指定します。これは基点から離れるほどスコアが低くなるように調整されています。

以下のいずれかの中から選択します。

  • gauss (ガウス関数)
  • exp (指数関数)
  • linear (線形関数)

パラメータと減衰の形状については以下のグラフを見てください。

いずれもoriginから offset の範囲内では減衰が許容され、それより離れると減衰が始まります。 offset+scaleの位置で、スコアがdecayの値(デフォルト0.5)と一致するように減衰します。

note
  • ガウス関数はベル曲線の形状をしており中心から離れるにつれてスコアが緩やかに減少するのに対し、指数関数では急激にスコアが減少しますが、decayの点で緩やかさが逆転します。
  • 関連性が高い検索結果を優先する場合は、指数関数が適しているかもしれませんね。

この例では女性ユーザのうち、登録した3か月前を基点として±12時間を減衰対象から除外、1週間でスコアが半減するようにしてみました。

  • ./search.sh params/function_score_decay.yaml | jq '.hits.hits[] | {_score, sex: ._source.sex, created_at: ._source.created_at, updated_at: ._source.updated_at}' + curl --data-binary @params/function_score_decay.yaml -H 'Content-Type: application/yaml' -H 'Accept: application/json' -X POST 'http://localhost:9200/profile1/_search?pretty' % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 19082 0 18835 100 247 381k 5122 --:--:-- --:--:-- --:--:-- 423k { "_score": 0.7031874, "sex": "F", "created_at": "2023-09-05T20:02:40.955287", "updated_at": "2023-11-11T23:03:27.298523" } { "_score": 0.7027179, "sex": "F", "created_at": "2023-09-05T06:47:06.221092", "updated_at": "2023-11-29T20:11:49.644819" } { "_score": 0.7013432, "sex": "F", "created_at": "2023-09-05T01:39:33.283513", "updated_at": "2023-11-02T01:37:50.197781" } { "_score": 0.70088935, "sex": "F", "created_at": "2023-09-05T00:27:17.677465", "updated_at": "2023-11-08T02:12:02.108093" } { "_score": 0.700737, "sex": "F", "created_at": "2023-09-06T23:55:19.946102", "updated_at": "2023-11-05T11:53:57.922462" } { "_score": 0.69444716, "sex": "F", "created_at": "2023-09-07T10:34:02.108701", "updated_at": "2023-11-03T07:47:23.171326" } { "_score": 0.6935094, "sex": "F", "created_at": "2023-09-04T12:14:41.557266", "updated_at": "2023-11-09T05:36:58.650730" } { "_score": 0.67989737, "sex": "F", "created_at": "2023-09-03T22:58:00.021651", "updated_at": "2023-11-07T13:37:16.256697" } { "_score": 0.66394746, "sex": "F", "created_at": "2023-09-08T12:21:13.360973", "updated_at": "2023-11-22T01:47:47.269392" } { "_score": 0.65633726, "sex": "F", "created_at": "2023-09-08T16:59:08.820188", "updated_at": "2023-11-22T23:42:25.857062" }

Function score query | Elasticsearch Guide [8.11] | Elastichttps://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html

Aggregations

queryで該当したドキュメントを集計します。

aggs キーの下に、集計値を格納するフィールド名を書きます。ここはなんでもOK。

全体に対して集計をかける場合、直下に集計関数を書きます。 グルーピングして集計する場合は、termsに条件 を書きさらに aggs キーを書きます。

  • ./search.sh params/aggs.yaml | jq .aggregations + curl --data-binary @params/aggs.yaml -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 20654 0 20210 100 444 2218k 49898 --:--:-- --:--:-- --:--:-- 3361k { "saving_by_blood_group": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "O-", "doc_count": 145, "saving_total": { "value": 4.13440706E+9 }, "saving_avg": { "value": 28513152.137931034 } }, { "key": "O+", "doc_count": 144, "saving_total": { "value": 7326885363 }, "saving_avg": { "value": 50881148.354166664 } }, { "key": "A+", "doc_count": 126, "saving_total": { "value": 7887169511 }, "saving_avg": { "value": 62596583.42063492 } }, { "key": "B-", "doc_count": 121, "saving_total": { "value": 7.27326864E+9 }, "saving_avg": { "value": 60109658.18181818 } }, { "key": "B+", "doc_count": 120, "saving_total": { "value": 6985464864 }, "saving_avg": { "value": 58212207.2 } }, { "key": "A-", "doc_count": 118, "saving_total": { "value": 8152664655 }, "saving_avg": { "value": 69090378.4322034 } }, { "key": "AB-", "doc_count": 116, "saving_total": { "value": 8201469476 }, "saving_avg": { "value": 70702323.06896552 } } ] }, "saving_total": { "value": 5.514996109E+10 }, "saving_avg": { "value": 55149961.09 } }
note

SearchAfter

指定したドキュメント以降のドキュメントを取得するためのパラメータです。ページング用ですね。 Firestoreを使ったことがあれば、startAfterと同じようなものだと言えばわかりやすいでしょうか。ちなみに Before はない。

最後に取得したドキュメントのフィールドを sort パラメータに指定した順番で指定します。

今回の例では blood_group, ssnでソートして取得した最後のドキュメントから取得した O-, 025-03-1465 を search_after で指定します。

関係ないですがssnは社会保障番号で、マイナンバーみたいなもんです。

1ページ目
    • ./search.sh params/sort.yaml | jq '.hits.hits[] | {id: ._id, blood_group: ._source.blood_group, ssn: ._source.ssn}' + curl --data-binary @params/sort.yaml -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 9980 0 9846 100 134 1183k 16498 --:--:-- --:--:-- --:--:-- 2436k { "id": "ec1b895d-e084-4faf-8bea-05a4b39e68ae", "blood_group": "O-", "ssn": "007-69-0929" } { "id": "0e79b81b-52e3-4e59-9b21-4e0f4fcb26fb", "blood_group": "O-", "ssn": "016-93-2125" } { "id": "f4322487-f12a-4d3e-9c1c-3efc4c9d9a95", "blood_group": "O-", "ssn": "020-24-4560" } { "id": "e2095aaf-943c-4239-95b1-ada58e042739", "blood_group": "O-", "ssn": "024-40-7392" } { "id": "997af022-b0ba-4d83-8758-fa4edd00e33a", "blood_group": "O-", "ssn": "025-03-1465" }
2ページ目
    • ./search.sh params/search_after.yaml | jq '.hits.hits[] | {id: ._id, blood_group: ._source.blood_group, ssn: ._source.ssn}' + curl --data-binary @params/search_after.yaml -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 10038 0 9863 100 175 1034k 18801 --:--:-- --:--:-- --:--:-- 1633k { "id": "5a6bf2a3-0d88-4c3b-ba76-f8b086654692", "blood_group": "O-", "ssn": "052-31-3427" } { "id": "aba1fe4c-98e8-47fb-96d1-b5014603d579", "blood_group": "O-", "ssn": "076-87-0396" } { "id": "af32883f-7c9d-4fbe-806f-4f4df7297944", "blood_group": "O-", "ssn": "084-13-5037" } { "id": "199be4c0-98e8-4329-a0d3-9b2be292c7e4", "blood_group": "O-", "ssn": "091-71-6945" } { "id": "da0f8531-9af4-48bf-ac13-1dce21b79d52", "blood_group": "O-", "ssn": "094-14-7782" }
note
  • ページング用途なので当然といえば当然ですが、start_afterに一致したドキュメントは検索結果に含まれません。
  • 1ページ目と2ページ目の境界(5,6件目)を見てみます。
    • + curl --data-binary @params/sort_and_from.yaml -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 4328 0 4181 100 147 429k 15476 --:--:-- --:--:-- --:--:-- 704k { "id": "997af022-b0ba-4d83-8758-fa4edd00e33a", "blood_group": "O-", "ssn": "025-03-1465" } { "id": "5a6bf2a3-0d88-4c3b-ba76-f8b086654692", "blood_group": "O-", "ssn": "052-31-3427" }
  • search_afterに指定した値に該当するレコードがなくてもエラーにはなりません。 その次のドキュメントからヒットします。
  • 例:025-03-1464は存在しない
    • ./search.sh params/search_after2.yaml | jq '.hits.hits[] | {id: ._id, blood_group: ._source.blood_group, ssn: ._source.ssn}' + curl --data-binary @params/search_after2.yaml -H 'Content-Type: application/yaml' -H "Accept: application/json" -X POST 'http://localhost:9200/profile1/_search?pretty' % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 9980 0 9805 100 175 1213k 22185 --:--:-- --:--:-- --:--:-- 1949k { "id": "997af022-b0ba-4d83-8758-fa4edd00e33a", "blood_group": "O-", "ssn": "025-03-1465" } { "id": "5a6bf2a3-0d88-4c3b-ba76-f8b086654692", "blood_group": "O-", "ssn": "052-31-3427" } { "id": "aba1fe4c-98e8-47fb-96d1-b5014603d579", "blood_group": "O-", "ssn": "076-87-0396" } { "id": "af32883f-7c9d-4fbe-806f-4f4df7297944", "blood_group": "O-", "ssn": "084-13-5037" } { "id": "199be4c0-98e8-4329-a0d3-9b2be292c7e4", "blood_group": "O-", "ssn": "091-71-6945" }
warning
  • sortに指定したフィールド数と一致しない場合、 search_after has 1 value(s) but sort has 2. みたいに言われます。

Paginate search results | Elasticsearch Guide [8.11] | Elastichttps://www.elastic.co/guide/en/elasticsearch/reference/current/paginate-search-results.html

参考資料

Elasticsearchの検索スコアリング(boost_mode、score_modeのsumとmultiplyの噛み合わせについてもう少し) - はてだBlog(仮称)はじめに この記事は次の記事のちょっとだけ補足(つづき)です。 itdepends.hateblo.jp 記事の概要 前の記事では、ひとことでいうとスコアリングは文字通り加点方針(条件に該当するとプラスが重なる方針)がオススメみたいなところを示唆しておりました。 スコアリングには、掛け算や平均をとったりということもできますが、加点の方が感覚的にわかりやすく・傾向も予測しやすいし、思ったより調子が悪い場合に、他の良いところを損なわずに調整するということも比較的やりやすいかなという思いからでした。 ただ、どこまで複雑にするかはともかく、やっぱり掛け算方式などにしたい場合もあるよね、ということで、私…https://itdepends.hateblo.jp/entry/2019/06/21/010941

ElasticsearchのBucket aggregationsのさわり - はてだBlog(仮称)ElasticsearchのAggregationsは種類が豊富ゆえに、嬉しい悲鳴なのですが、私のようなメモリが小さい人間はどれがどれというところの理解が大変です。 実際は、似た演算は、クエリの形とパラメータ、得られるバケット(演算結果)の形式が似ているので、同じような用途の内容違いのものを形から入って理解しましょうということで、記事をまとめてみました。 今回は、Bucket aggregatios、Metrics ...、Pipeline ...、でいうところのBucket aggregationsの俯瞰照会です。 www.elastic.co 事前準備:サンプルデータのインポート 1.時系…https://itdepends.hateblo.jp/entry/2021/07/07/225430

Elasticsearch の検索(Query DSL)について調べてみた! - BookStore’s Code ...前回に引き続き Elasticsearch についてです。今回は検索の Query DSL について調べてみようかと。 チートシート発見したので、ドキュメント詳しく読むのがめんどくさいときは参考にしようと思います。 https://elasticsearch-cheatsheet.jolicode.com/ QueryDSL Elasticsearch は検索の種類が Query DSL と、SQL DSL とあります。どちらかというと Query DSL の方が一般的かなーと思います。チュートリアルも Query DSL で書かれていましたし。 Query DSL | 公式サイト Query…https://baubaubau.hatenablog.com/entry/2020/07/01/193757

Elasticsearchの基本クエリのざっくりしたまとめhttps://zenn.dev/osshy/articles/358e3d0ccc34fa

Elasticsearchのbool queryを利用してAND OR NOTを書いてみる - Qiita初めてElasticsearchのクエリをビルドしたのでいろいろハマりました。SQLの世界観とちょっと違っていて、なれるまで時間がかかると思います。でも、なれたら複雑な検索条件をSQLより簡単に書け…https://qiita.com/vanhuyz/items/04a6871ae5f53ba5a97f