画像とタグやメッセージとそのコメントなど1対多の関係があるデータをelasticsearchに入れて検索させたい場合、nestedを使うというメモ
主に使ったもの
Elasticsearch5
elasticsearch-rails
indexの作成
nested queryを使いたい場合、indexを作成する時はelasticsearch-railsを使って以下のように書きます。
mapping _source: { enabled: true },
_all: { enabled: true, analyzer: "kuromoji_analyzer" } do
indexes :id, type: 'long', index: 'not_analyzed'
indexes :body, type: 'string', analyzer: 'kuromoji_analyzer'
indexes :comments, type: 'nested' do
indexes :user_id, type: 'long'
indexes :message_id, type: 'long'
indexes :body, type: 'string', analyzer: 'kuromoji_analyzer'
end
indexes :created_at, type: 'date'
indexes :updated_at, type: 'date'
end
こう書くことでcommentsのところが
"comments":{
"type":"nested", "properties":{
"user_id":{"type":"long"},
"message_id":{"type":"long"},
"body":{"type":"string","analyzer":"kuromoji_analyzer"}
}
}
以下のようなindex定義でElasticsearchに登録されます。
検索する時のquery
例ばbodyとcomments.bodyの二つのカラムの中のどれかにキーワード検索したい場合、以下のように書くと検索できます。
{
"query":{
"bool":{
"must":[
{"term":{"school_id":1}}
],
"should":[
{
"simple_query_string":{
"query":""テスト投稿"",
"fields":["body"],
"default_operator":"and"
}
},
{
"nested":{ <<<<<<<< ここに注目
"path":"comments",
"query":{
"simple_query_string":{
"query":""テスト投稿"",
"fields":["comments.body"],
"default_operator":"and"
}
}
}
}
],
"minimum_should_match":1
}
},
"from":0,
"size":10,
"sort":[{"created_at":{"order":"desc"}}]
}
or検索になるので、shouldの中にbodyとcomments.bodyの検索queryを書いてます。で、どれか一方に必ずヒットするようにしたいにで、「minimum_should_match」を定義してます。
nestedを使うことで階層的なデータを格納し検索するのが、楽になります。