Elasticsearchのmapping
elasticsearchDynamic mappingがあるので、自分で設定しなくてもデータは入るが、 自分でやるとindexやanalyzerなどの設定が詳細にできるし、意図しないmappingを避けることもできる。 バージョンは5.2。
$ curl -XPOST 'localhost:9200/test_hoge/fuga?pretty' -d'
{
"name": 0
}
'
$ curl -XPOST 'localhost:9200/test_hoge/fuga?pretty' -d'
{
"name": "sambaiz"
}
'
{
"error" : {
"root_cause" : [
{
"type" : "mapper_parsing_exception",
"reason" : "failed to parse [name]"
}
],
"type" : "mapper_parsing_exception",
"reason" : "failed to parse [name]",
"caused_by" : {
"type" : "number_format_exception",
"reason" : "For input string: \"sambaiz\""
}
},
"status" : 400
}
Mapping parameters
index
falseにするとindexしない。クエリで必要ないものはfalseにする。
"memo": { "type": "text", "index": false }
store
デフォルトでフィールドはindexされるがstoreはされず、metaの_sourceとしてオリジナルのJSONがstoreされている。
サイズの大きなフィールドがあるなど、選んでstoreする場合はtrueにする。stored_fieldsで必要なものだけとってくることができる。
"memo": { "type": "text", "store": true }
Meta fields
_all
全てのフィールドをスペースでつなげた一つの文字列にしてanalyzeし、indexする。storeはされない。
フィールドの区別なく検索できたりするがindexするのにコストがかかるので必要ないならfalseにする。
"_all": { "enabled": false }
_source
オリジナルのJSONを含み、indexはされずstoreされる。
無効にするとストレージを節約できるが、 まずはcompression levelを上げてみる。 無効にするとupdateやreindexができなくなったりするので有効のままにしている。
"_source": { "enabled": false }
analysis
textをどのようにanalyzeするか。
Analyzerは Character filtersで文字列を加工してTokenizerでトークンに分割してからToken filtersでトークンを取り除いたり変更したりするもの。 自分でこれらを組み合わせて定義することもできる。
日本語のAnalyzerとしてkuromojiがある。
$ bin/elasticsearch-plugin install analysis-kuromoji
"name": { "type": "keyword", "analyzer": "kuromoji"}
$ curl -XGET 'localhost:9200/_analyze?pretty' -d '
{
"analyzer" : "kuromoji",
"text" : "Character filtersで文字列を加工します"
}'
{
"tokens" : [
{
"token" : "character",
"start_offset" : 0,
"end_offset" : 9,
"type" : "word",
"position" : 0
},
{
"token" : "filters",
"start_offset" : 10,
"end_offset" : 17,
"type" : "word",
"position" : 1
},
{
"token" : "文字",
"start_offset" : 18,
"end_offset" : 20,
"type" : "word",
"position" : 3
},
{
"token" : "列",
"start_offset" : 20,
"end_offset" : 21,
"type" : "word",
"position" : 4
},
{
"token" : "加工",
"start_offset" : 22,
"end_offset" : 24,
"type" : "word",
"position" : 6
}
]
}
datatype
文字列
5.Xからstringは廃止され textと keywordになった。
textはメールの文章のようなfull-textの値で、ある単語がそれぞれの文章に含まれるかということを調べることができる。 メールアドレスのようなデータの場合はkeywordを使う。
"email": { "type": "keyword" }
数値
long(64bit), integer(32bit), short(16bit, ~32767), byte(8bit, ~127), double, floatとか。
"age": { "type": "short" }
日付
こんな感じ。
"date": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
Boolean
"success": { "type": "boolean" }
Object
propertiesの中に書く。
"hoge": {
"properties": {
"fuga": { "type": "boolean" }
}
}
nested
objectの配列。
"hoge": {
"type": "nested"
"properties": {
"fuga": { "type": "boolean" }
}
}
"hoge": [{"fuga": true}]
登録
$ curl -XPUT 'localhost:9200/test_index?pretty' -d'
{
"mappings": {
"test_type": {
"_all": { "enabled": false },
"properties": {
"name": { "type": "keyword", "store": true },
"description": { "type": "text", "analyzer": "kuromoji" },
"memo": { "type": "text", "index": false }
}
}
}
}
'
$ curl -XPOST 'localhost:9200/test_index/test_type?pretty' -d'
{
"name": "sambaiz",
"description": "青い海",
"memo": "白い空"
}
'
logstashのようにindex名に日付が付いているような場合は indices-templateで設定する。
$ curl -XPUT localhost:9200/_template/hogefuga-template -d '
{
"template" : "hogefuga-*",
"mappings" : {
...
}
}
'
取得
まずはデータが入っていることを確認。
$ curl 'localhost:9200/test_index/test_type/_search?pretty'
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 1.0,
"hits" : [
{
"_index" : "test_index",
"_type" : "test_type",
"_id" : "AVodMAubr8EtIroFs0eP",
"_score" : 1.0,
"_source" : {
"name" : "sambaiz",
"description" : "青い海",
"memo" : "白い空"
}
}
]
}
}
stored_fieldsを付けてリクエスト。_sourceが含まれず、storeがtrueなnameだけが返ってくる。
$ curl 'localhost:9200/test_index/_search?pretty&stored_fields=name,description,memo'
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 1.0,
"hits" : [
{
"_index" : "test_index",
"_type" : "test_type",
"_id" : "AVodMAubr8EtIroFs0eP",
"_score" : 1.0,
"fields" : {
"name" : [
"sambaiz"
]
}
}
]
}
}
クエリを付けてリクエスト。indexされてないmemoではひっかからない。
$ curl -XPOST 'localhost:9200/test_index/test_type/_search?pretty' -d '
{
"query":{
"query_string":{
"default_field" : "description",
"query": "青い海"
}
}
}'
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 1,
...
}
}
$ curl -XPOST 'localhost:9200/test_index/test_type/_search?pretty' -d '
{
"query":{
"query_string":{
"default_field" : "memo",
"query": "白い空"
}
}
}'
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 0,
"max_score" : null,
"hits" : [ ]
}
}