LoginSignup
13
8

More than 5 years have passed since last update.

elasticsearch5.0.0でfieldsを指定したクエリを使うときは store:true をつけておくのがよさげ

Last updated at Posted at 2016-07-06

概要

elasticsaerchで検索クエリで、取得したいfieldsを指定して投げるときの注意点という名の個人用備忘録。

結論

2016/07/07 修正
そもそも、クエリでfields指定するよりは、_sourceからフィルタリングして取れないかを検討する。

どうしても、クエリでfieldsを使いたいんや、という場合は・・・
(2.3だと、store:trueとしていないstringのフィールドでもfieldsでとれていた。)

  • elasticsearch5.0以降で、クエリでfieldsを指定したいときは、mapping定義でstore:trueを入れておく
  • stored_fieldsだとUnknown key for a START_ARRAY in [stored_fields].というエラーになった・・・

試した環境

製品 バージョン
elasticsearch 5.0.0-alpha4
kibana 5.0.0-alpha4

elasticsearchはalpineをベースにしたDockerイメージで動かす。

ドキュメントの確認

Search and Query DSL changes

Search and Query DSL changesによると、fields parameterのところには、こんな風に書いてある

The fields parameter has been replaced by stored_fields. The stored_fields parameter will only return stored fields — it will no longer extract values from the _source.

たぶん、こういうことだと理解した。

  • fieldsパラメータは、stored_fieldsに置き換えられた(ので、そっちを使うと良いよ)
  • stored_fieldsパラメータは、storeされたフィールドしか返さないよ
  • stored_fieldsパラメータは、_sourceフィールドから(結果を)抽出するわけじゃないよ

stored_fieldsの確認

Fieldsを確認しますと、また気になる記述があります。

The stored_fields parameter is about fields that are explicitly marked as stored in the mapping, which is off by default and generally not recommended. Use source filtering instead to select subsets of the original source document to be returned.

mappingでstoredと設定されたものだけが対象だよ。デフォルトだとオフになっているから、source filteringを使うと良いかもねかもねそうかもね。

source filterringの確認

Source Filteringで、sourceのフィルタリング方法を確認しておきます。

いざ、実践

kibanaにあるConsoleを使っていろいろテストしてみます。

テストデータの生成

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "title": { 
          "type": "text"
        },
        "first_name": {
          "type": "text",
          "store": true
        },
        "last_name": {
          "type": "text",
          "store": true
        }
      }
    }
  }
}

PUT my_index/my_type/1
{
  "title": "Mr",
  "first_name": "Barry",
  "last_name": "White"
}

インデックスの確認

GET my_index/_search
{
  "query" : {
    "match_all": {}
  }
}

検索結果

{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 1,
    "hits": [
      {
        "_index": "my_index",
        "_type": "my_type",
        "_id": "1",
        "_score": 1,
        "_source": {
          "title": "Mr",
          "first_name": "Barry",
          "last_name": "White"
        }
      }
    ]
  }
}

fieldsを指定する

storeを指定していないフィールドの場合

store: trueとしなかった、titleフィールドを指定してみると、こんな結果になります。

クエリ

GET my_index/_search
{
  "query" : {
    "match_all": {}
  },
  "fields": ["title"]
}

結果がこちら。titleがどこにもありませんが、1件ヒットしていることが確認できます。

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 1,
    "hits": [
      {
        "_index": "my_index",
        "_type": "my_type",
        "_id": "1",
        "_score": 1
      }
    ]
  }
}

storeを指定したフィールドの場合

クエリ

GET my_index/_search
{
  "query" : {
    "match_all": {}
  },
  "fields": ["first_name", "last_name"]
}

結果がこちら。先ほどと異なり、first_nameとlast_nameが結果に含まれていることが確認できました。

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 1,
    "hits": [
      {
        "_index": "my_index",
        "_type": "my_type",
        "_id": "1",
        "_score": 1,
        "fields": {
          "last_name": [
            "White"
          ],
          "first_name": [
            "Barry"
          ]
        }
      }
    ]
  }
}

stored_fieldsを指定する

うまく結果が得られたfieldsでのクエリを少し編集して、fieldsをstored_fieldsに変えました。

GET my_index/_search
{
  "query" : {
    "match_all": {}
  },
  "stored_fields": ["first_name", "last_name"]
}

結果がこちら。悲しいパースエラー。

{
  "error": {
    "root_cause": [
      {
        "type": "parsing_exception",
        "reason": "Unknown key for a START_ARRAY in [stored_fields].",
        "line": 5,
        "col": 20
      }
    ],
    "type": "parsing_exception",
    "reason": "Unknown key for a START_ARRAY in [stored_fields].",
    "line": 5,
    "col": 20
  },
  "status": 400
}

sourceのfilterringを使う

store:trueを指定していなかったtitleと指定したlast_nameの2つを指定してみます。

GET my_index/_search
{
  "query" : {
    "match_all": {}
  },
  "_source": ["title", "last_name"]
}

結果がこちら。_sourceの中で指定したフィールドに絞られて結果が得られていることが確認できました。

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 1,
    "hits": [
      {
        "_index": "my_index",
        "_type": "my_type",
        "_id": "1",
        "_score": 1,
        "_source": {
          "last_name": "White",
          "title": "Mr"
        }
      }
    ]
  }
}

おまけ

2.3系でfieldsを試したときのsense

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "title": { 
          "type": "string"
        },
        "first_name": {
          "type": "string",
          "store": true
        },
        "last_name": {
          "type": "string",
          "store": true
        }
      }
    }
  }
}

PUT my_index/my_type/1
{
  "title": "Mr",
  "first_name": "Barry",
  "last_name": "White"
}

GET my_index/_search
{
  "query" : {
    "match_all": {}
  },
  "fields": ["title", "last_name"]
}

これで、結果はtitleとlast_nameと両方入る形。

{
  "took": 3,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 1,
    "hits": [
      {
        "_index": "my_index",
        "_type": "my_type",
        "_id": "1",
        "_score": 1,
        "fields": {
          "title": [
            "Mr"
          ],
          "last_name": [
            "White"
          ]
        }
      }
    ]
  }
}
13
8
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
8