そう言えば、elasticsearch勉強したことあるけれど、あまり検索にフォーカスしていなかったなっと思いました。mappingとか、indexとかその辺りの事中心だった気がします。(もう忘れたけれど)
term
って和訳すると、「用語」「言葉」って言うらしいです。
term
は完全一致で検索する時に使うみたいですね。 keyword
タイプのフィールドに使うのが一般的なのかも? term
クエリの説明ページではそんなこと書いてありませんが、 text
タイプのフィールドに使うのはオススメしないって言ってますね。
https://www.elastic.co/guide/en/elasticsearch/reference/8.3/query-dsl-term-query.html
逆に keyword
以外だとどんなフィールドに使うんだろうか? Numbers
boolean
とかかな? 忘れました。elasticsearchのデータタイプ全部使ったことないなと。
https://www.elastic.co/guide/en/elasticsearch/reference/8.3/mapping-types.html
公式ドキュメントに term
クエリを実行したケースと、 match
クエリを実行したケースの違いが載っていたので実際に手元で確認してみます。
まず、 text
タイプを一つ持つインデックスを作り、ドキュメントを作成しました。
PUT my-index { "mappings": { "properties": { "full_text": { "type": "text" } } } } PUT my-index/_doc/1 { "full_text": "Quick Brown Foxes!" }
以下のように、上記のドキュメントを term
クエリで検索しても結果が返ってきません。 full_text
フィールドは text
タイプなので、インデックスされるときにAnalyzerによって分析されるので、全く同じテキストで検索しても出てこないってことですね。
以下、公式ドキュメントより。
Because the full_text field no longer contains the exact term Quick Brown Foxes!, the term query search returns no results.
text
タイプに合った検索、match
クエリを使うとこのドキュメントを取得できます。
GET my-index/_search { "query": { "match": { "full_text": "Quick Brown Foxes!" } } } // response { "took" : 4, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 1, "relation" : "eq" }, "max_score" : 0.8630463, "hits" : [ { "_index" : "my-index", "_id" : "1", "_score" : 0.8630463, "_source" : { "full_text" : "Quick Brown Foxes!" } } ] } }
match
クエリなので、一部分だけでもヒットすればドキュメントを取ることができます。(このあたりの詳しい話は忘れました。多分Analyzerで保存されているテキストも、検索するテキストも、トークン化(だっけ?)して突合していたはず!)
GET my-index/_search { "query": { "match": { "full_text": "Quick" } } }
ちなみに、 term
クエリでも、 match
クエリでも、どちらでも検索できるようにしておきたい!というユースケースに対応できるようにelasticsearchでは、multi fieldという機能があります。こいつを使えば、どちらのクエリでもひっかけるようにできますね。
fields | Elasticsearch Guide [8.3] | Elastic
multi fieldは、一つのフィールドに対し複数のタイプを関連付けることができる機能です。なので、 text
と keyword
を同時に割り当てることができます(便利ですね)。おんなじ名前にはできないので、それぞれ別別のフィールド名を割り当てることになりますね。
例えば次のようにマッピングを定義しておけば、上記のドキュメントはどちらでもヒットするようにできます。
PUT my-index { "mappings": { "properties": { "full_text": { "type": "text", "fields": { "keyword": { "type": "keyword" } } } } } } PUT my-index/_doc/1 { "full_text": "Quick Brown Foxes!" } GET my-index/_search { "query": { "match": { "full_text": "Quick" // ←ヒットする! } } } GET my-index/_search { "query": { "term": { "full_text.keyword": "Quick Brown Foxes!" // ←ヒットする! } } }