Elasticsearchで条件にマッチしたワードをハイライト表示したいなんてことありますよね。 これを実現するために、条件にマッチした部分を検索結果から取得する方法になります。
準備
インデックス内容
フィールドをひとつだけ持つインデックスを作成して確認してみます。
{ "settings": { "number_of_shards": 1, "analysis": { "analyzer": { "kuromoji": { "type": "custom", "tokenizer": "kuromoji_tokenizer" } } } }, "mappings": { "_doc": { "properties": { "name": { "type": "text", "analyzer": "kuromoji" } } } } }
データ投入
JavaのClientを使って、2つのドキュメントを投入します。
fun main() { createClient().use { client -> val bulkRequest = BulkRequest().apply { add(IndexRequest("test", "_doc").apply { source(mapOf("name" to "あいうえお かきくけこ")) }) add(IndexRequest("test", "_doc").apply { source(mapOf("name" to "さしすせそ たちつてと")) }) } val response = client.bulk(bulkRequest, RequestOptions.DEFAULT) println(response.status()) } }
検索条件にマッチした部分を取得してみる
検索クエリー
検索クエリーを投げる際の、リクエストボディにhighlight
を追加してあげます。
また、highlight
にはハイライト表示したい(条件にマッチした部分を知りたい)フィールド名を指定してあげます。
{ "query": { "bool": { "filter": { "terms": { "name": ["あい", "たち"] } } } }, "highlight": { "fields": { "name": { } } } }
検索結果
検索結果の各ドキュメントごとに、highlight
から検索条件にマッチした部分を取得できます。
デフォルトでは、em
タグでマッチした部分が囲まれて返ってきます。
{ "took": 8, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": 2, "max_score": 0.0, "hits": [ { "_index": "test", "_type": "_doc", "_id": "_3tmSnoBBFTrBATTDpDa", "_score": 0.0, "_source": { "name": "あいうえお かきくけこ" }, "highlight": { "name": [ "<em>あい</em>うえお かきくけこ" ] } }, { "_index": "test", "_type": "_doc", "_id": "AHtmSnoBBFTrBATTDpHa", "_score": 0.0, "_source": { "name": "さしすせそ たちつてと" }, "highlight": { "name": [ "さしすせそ <em>たち</em>つてと" ] } } ] } }
JavaのClientで試してみる
検索用のリクエスト(SearchRequest
)のhighlighter
にハイライト表示したいフィールド名を指定してあげます。
検索結果からは、検索にヒットしたドキュメントごとhighlightFields
からハイライト表示されたフラグメントが取得できます。
コード
fun main() { createClient().use { client -> val searchRequest = SearchRequest("test").apply { types("_doc") source(SearchSourceBuilder().apply { query(QueryBuilders.boolQuery().apply { filter(QueryBuilders.termsQuery("name", "あい", "かき", "たち")) }) highlighter(HighlightBuilder().apply { field("name") }) }) } val response = client.search(searchRequest, RequestOptions.DEFAULT) println(response.status()) response.hits.hits.forEach { it.highlightFields.forEach { println("it = ${it.value}") } } } }
実行結果
APIを直接呼び出したときと同じように、ハイライト表示対応されたフラグメントが取得できていることが確認できます。
it = [name], fragments[[<em>あい</em>うえお <em>かき</em>くけこ]] it = [name], fragments[[さしすせそ <em>たち</em>つてと]]