はじめに
全文検索エンジンElasticsearchの勉強を始めて1ヶ月くらいの雑魚エンジニアです.まだまだ理解できていない部分が多いのが現状...(変なところあったら,コメント下さい)
今回はタイトルの通り,マッピングでintegerを指定していたのに,stringになっていて,ハマったのでその考察です.
Elasticsearchでは自動で型推論が行われるので,stirngを入れてもintにしてくれる...と思っていたのですが,検索をしたときの結果がstirngになっているときがありました.
環境
※いずれもDockerで構築
Elasticsearch 7.1.0
kibana 7.1.0
マッピングを設定
以下のコマンドは全て,kibanaのコンソール上で実行しています.(シェルからcurlコマンドを叩いてもいいのですが,入力しずらいので)
型がintegerでnumber_int
というフィールドがあるマッピングを設定しておきます.
PUT my_index
{
"mappings": {
"properties": {
"number_int": {
"type": "integer"
}
}
}
}
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "my_index"
}
マッピングの確認
正しくマッピングができているか念の為,確認します.
GET my_index/_mapping
{
"my_index" : {
"mappings" : {
"properties" : {
"number_int" : {
"type" : "integer"
}
}
}
}
}
(わーい,できてる〜)
stringのデータを登録してみる
マッピングではintegerとしているのですが,
「型推論が行われるから大丈夫だろ」
と思ったマヌケな僕は,stringのデータを登録してみます.
PUT my_index/_doc/1
{
"number_int": "10"
}
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
(わーい,無事登録できたよー)
が,しかし...
検索をかけてみる
number_int
が20以下で検索をかけてみます.すると(結果をよく見てください)
GET my_index/_search
{
"query" : {
"range" : {
"number_int" : {
"lte" : 20
}
}
}
}
{
"took" : 663,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"number_int" : "10"
}
}
]
}
}
"number_int" : "10"
となっています.
マッピングの型はintegerなのにあれ?
string???
なんで???
型変換してくれないの???
検索するときはinteger(20以下の20)にしているのに???
試しにintegerのデータを登録してみる
PUT my_index/_doc/1
だと先ほどのドキュメントを上書きしてしまうため,2に変更しています.
PUT my_index/_doc/2
{
"number_int": 14
}
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "2",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 3,
"_primary_term" : 1
}
もう一回,検索をかけてみる
もう一度,number_int
が20以下で検索してみます.
すると...
GET my_index/_search
{
"query" : {
"range" : {
"number_int" : {
"lte" : 20
}
}
}
}
{
"took" : 550,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"number_int" : "10"
}
},
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"number_int" : 14
}
}
]
}
}
"_id" : "1"
の方は"number_int" : "10"
と先ほどと変わらずstringのままで,"_id" : "2",
の方は,"number_int" : 14
とintegerになっています.
もはや,わけわかめー
どうやら,_source
field は,インデックス保存時に渡された値を返しているらしい
最初,Elastcisearchの公式が最も情報量が豊富なので探してみたのですが,よくわかりませんでした.
というわけで,ゴリ押しでググりまくって見つけました.
参考 : 今日のElasticsearch学び Vol.2 - Mappings編
_source fieldには実際に投入したドキュメントのそのままの値が入っている。つまりCharFilterとかTokenizerとかそういうのが全くかかっていない状態のものが入っている。詳しくは_source fieldを参照。
どうやら_source
field の仕様のようです(マッピングが間違えているとばかり思っていました...).公式のリンクも貼ってくださっていたので,みてみます.
参考(公式) : _source field
The _source field contains the original JSON document body that was passed at index time.
ということから,ドキュメントとして登録されているのは型を自動で変換して,integerになっているが,
_source
fieldに含まれるのは,インデックス保存時に渡された値なので,stringで返ってきたり,integerで返ってきていたみたいです.
Elasticsearchを扱うときは型に気をつけましょう〜