概要
前回と同じく、検索した時に「部分一致させたいけど、上位に出るのは前方一致してるものがいいなぁ」といった時の対応。
今回はcopy_to
を使います。
元々の経緯としてはフィールド構造が異なる複数の対象に対してTopHitsクエリを用いていたのですが、何かクエリを揃える方法はないかなぁと思って調べてみたところあったので使ってみました。
検索文字 | デフォルト | 希望 |
---|---|---|
fa | fate refactor |
fate refactor |
環境
- Ubuntu 14.04
- Elasticsearch 2.2.0
マッピング
前回は1つのフィールドに対し、複数のanalyzerを指定しました。
今回はフィールドをコピーすることで、そちらも検索対象にします。
元々存在するterm
というフィールドを、raw
という新フィールドにコピーします。
term
とraw
、それぞれ別のanalyzerを使うことで標題の件を解決します。
{ "settings": { "analysis": { "analyzer": { "ngram_analyzer": { "tokenizer": "ngram_tokenizer" } }, "tokenizer": { "ngram_tokenizer": { "type": "nGram", "min_gram": 2, "max_gram": 3, "token_chars": [ "letter", "digit" ] } } } }, "mappings": { "internet": { "_all": { "enabled": false }, "dynamic": false, "properties": { "raw": { "type": "string", "index": "not_analyzed" }, "term": { "type": "string", "index": "analyzed", "analyzer": "ngram_analyzer", "copy_to": "raw" } } } } }
データ用意
curl -s -XPOST localhost:9200/test/_bulk -d ' {"index": {"_type": "internet", "_id": "1"}} {"term": "fate"} {"index": {"_type": "internet", "_id": "2"}} {"term": "refactor"} {"index": {"_type": "internet", "_id": "3"}} {"term": "facebook"} '
クエリ
今まで
curl localhost:9200/test/internet/_search?pretty -d ' { "query": { "match": { "term": { "query": "fa" } } }, "size": 5, "from": 0 } '
結果
fate refactor facebook
今回
- 部分一致:match query(ngram)
- 前方一致:prefix query
の2要素でスコアを付けます。
term
の方は部分一致、raw
の方は前方一致のスコアをつけます。
curl localhost:9200/test/internet/_search?pretty -d ' { "query": { "bool": { "should": [ { "match": { "term": { "query": "fa" } } }, { "prefix": { "raw": { "value": "fa" } } } ] } }, "size": 5, "from": 0 } '
結果
fate facebook refactor
prefix queryによってスコアが加算されたため、順番が変わり要望通りになりました。