@johtaniの日記 2nd

@johtani ‘s blog 2nd edition

Nested Objectのフィールドの奇妙な動作

今年初の「突撃!隣のElasticsearch」ということで、Wantedlyさんにおじゃましました。

※写真を自分でも撮ったのですが、画像が壊れてたので、一緒に行ったペンギン先生の写真を拝借しました。

第3回のElasticsearch勉強会を開催中にES使ってるってツイートを見つけたので、アタックかけて遊びに行きました。 交渉に快諾いただきありがとうございました!

WantedlyさんがどのようにElasticsearchを使用されているかはきっと、ブログを書いてくれると思うので期待しておくとして、書いてくれました!! 「実践!Elasticsearch」 そこで、nestedでハイライトがなんかうまくいかないって話があったので、ちょっと調べてみました。 (※まだ、調査中です)

前提条件

再現する手順はgistにあります。(Senseに貼り付ければ動作します。ただし、elasticsearch-analysis-kuromojiが必要です。)https://gist.github.com/johtani/9184287

なお、このマッピングやデータはWantedlyさんとは全く関係ありません。

nestedフィールド内部のデータに対して、検索しハイライトしようとするとうまく動作しないという状況です。 マッピングは以下のとおり。

1
2
3
4
5
6
7
8
9
10
11
12
  "books" : {
    "properties": {
      "book" : {
        "type": "nested",
        "properties": {
          "title" : { "type": "string", "analyzer": "kuromoji", "store": "no"},
          "contents" : {"type": "string", "analyzer": "kuromoji", "store": "yes"}
        }
      }
    }
  }
}

このマッピングの特徴は以下のとおり。

  • _sourceは保存される(デフォルト値)
  • booknestedなオブジェクト
  • titlestore : no
  • contentsstore : yes

動作の挙動をわかりやすくするため、titlecontentsstore属性に違いを持たせてあります。

問題点

nestedクエリを使って、検索した時にハイライトが返ってきません。 次のクエリを実行するとわかります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

GET /bookstore/books/_search
{
  "_source" : ["book.title","book.contents"],
  "fields": [
    "book.title",
    "book.contents"
  ], 
  "query": {
    "nested": {
      "path": "book",
      "query": {
        "query_string" : {
          "query" : "Solr",
          "fields" : ["book.title", "book.contents"]
        }
      }
    }
  },
  "highlight": {
    "pre_tags": ["<b>"], 
    "post_tags": ["</b>"],
    "fields": {
      "*": {}
    }
  }
}

結果はこちら。 ハイライトがありません。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
   "took": 3,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 1,
      "max_score": 0.5,
      "hits": [
         {
            "_index": "bookstore",
            "_type": "books",
            "_id": "1",
            "_score": 0.5,
            "_source": {
               "book": {
                  "title": "Apache Solr入門",
                  "contents": "Apache Solrについて日本語で書かれた唯一の書籍です。SolrはLuceneをコアにした検索サーバです。"
               }
            }
         }
      ]
   }
}

次に、ハイライトが帰ってくるパターン。 nestedクエリではなく、_allを対象としたクエリを投げます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
  "_source" : ["book.title","book.contents"],
  "fields": [
    "book.title",
    "book.contents"
  ], 
  "query": {
    "query_string" : {
      "query" : "Solr",
      "fields": [
        "_all"
      ]
    }
  },
  "highlight": {
    "pre_tags": ["<b>"], 
    "post_tags": ["</b>"], 
    "fields": {
      "book.title" : {},
      "book.contents": {}
    }
  }
}

この場合の結果は次の通り。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
   "took": 2,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 1,
      "max_score": 0.27063292,
      "hits": [
         {
            "_index": "bookstore",
            "_type": "books",
            "_id": "1",
            "_score": 0.27063292,
            "_source": {
               "book": {
                  "title": "Apache Solr入門",
                  "contents": "Apache Solrについて日本語で書かれた唯一の書籍です。SolrはLuceneをコアにした検索サーバです。"
               }
            },
            "highlight": {
               "book.title": [
                  "Apache <b>Solr</b>入門"
               ]
            }
         }
      ]
   }
}

ハイライトが返ってきています。

考察(原因は未特定)

残念ながら、まだ調査してません。 まずは、現象が理解できたというだけです。 問題点が実は2つありそうです。

問題点1:nestedクエリの場合に、ハイライトされない。

nestedクエリではハイライトが動作していないようです。 想像ですが、検索に利用されたクエリで指定されているフィールドをハイライタ(ハイライトを実行するモジュール)が認識できてないのではないかと。 なぜ認識できていないのかという点を調査する必要がありそうです。

考察(試してみたパターン)

nestedではないクエリで、ハイライトが動作しているのですが、 "book.title" : {"require_field_match" : true},にした場合は、ハイライトが返ってこないです。 このオプションは、検索対象のフィールドでマッチした文字列だけがハイライトされるオプションになります。 したがって、book.titleフィールドに対する検索でSolrという文字を検索していないことになります。 _allに対するクエリであるためです。 このため、例えば、titleだけを検索対象にしたのに、contentsSolrという文字が入っていてもハイライトされてしまうという状況が発生します。

問題点2 store : yesのデータがハイライトできない。

GithubにIssueをあげました。https://github.com/elasticsearch/elasticsearch/issues/5245 (2014/02/25追記)

nestedオブジェクトにあるデータのうち、store : noのものだけがハイライト結果として返ってきました。

考察

なぜ、store : yesのデータがハイライトされないかを調べるために、fieldsパラメータをリクエストに追加してみました。

1
2
3
4
5
6
7
8
{
  "_source" : ["book.title","book.contents"],
  "fields": [
    "book.title",
    "book.contents"
  ], 
...
}

すると、fieldsの戻り値は次のとおりです。

1
2
3
4
5
6
7
...
            "fields": {
               "book.title": [
                  "Apache Solr入門"
               ]
            },
...

このことから、store : noのデータの場合、_sourceから値を取得して返却しているというのがわかります。 ハイライトがされない原因も、fieldsで値が取れていないのも同じ原因であると思われます。 なぜなら、ハイライトは、保存された文字列を内部で取り出し利用して、ハイライトタグを埋め込むという動作をするためです。

参考?

これらの問題点についてですが、次のIssueが関係あるかもしれません。

Return matching nested inner objects per hit #3022

今後?

残念ながら、現時点では、問題点がどんなものかというのを理解しただけとなります。 デバッグしたりソースを追っかけたりして何が問題なのかを調べて行ってみようかなぁと。

なにか、気づいたことなどあればコメントしてもらえると助かります。

Comments