初めてここで質問させていただきます
現在、RailsのGemであるSearchkick経由でkuromojiプラグインを使っているのですが、Kibanaコンソールではちゃんと形態素解析され目的の検索結果がでるのに、localhost:3000で実際に検索するとヒットしません。
前提・実現したいこと
各カテゴリーで良質な情報を提供するサイトのデータベースを作っています。Railsで「searchkick」と「kuromoji」 を使って、投稿(Post
)の検索機能を実装しているところです。
以下のER図のように、PostとCategoryは多対多で、かつCategoryはAncestryを使って多階層化されています。
例えばnameが「世界名所100選」であるPostが、Category「絶景」をリレーションとして持っているとき、「日本の絶景」と検索してもヒットするようにしたいです。
発生している問題・エラーメッセージ
kibanaコンソールでは以下のようにGETすると上手くヒットするのですが、実際の(Rails s で立ち上げたlocalhost:3000にて)検索窓に「日本の絶景」と打ち込んでも何もヒットしません。
GET /posts_development/_search
{
"query": {
"multi_match": {
"fields": [ "name", "description", "category_name"],
"query": "日本の絶景",
"analyzer": "searchkick_index"
}
}
}
該当のソースコード
インデックスの設定
GET /posts_development?pretty
返り値↓
{
"posts_development_20200709141330421" : {
"aliases" : {
"posts_development" : { }
},
"mappings" : {
"dynamic_templates" : [
{
"string_template" : {
"match" : "*",
"match_mapping_type" : "string",
"mapping" : {
"fields" : {
"analyzed" : {
"analyzer" : "searchkick_index",
"index" : true,
"type" : "text"
}
},
"ignore_above" : 30000,
"type" : "keyword"
}
}
}
],
"properties" : {
"category_name" : {
"type" : "keyword",
"fields" : {
"analyzed" : {
"type" : "text",
"analyzer" : "searchkick_index"
}
},
"ignore_above" : 30000
},
"description" : {
"type" : "keyword",
"fields" : {
"analyzed" : {
"type" : "text",
"analyzer" : "searchkick_index"
}
},
"ignore_above" : 30000
},
"name" : {
"type" : "keyword",
"fields" : {
"analyzed" : {
"type" : "text",
"analyzer" : "searchkick_index"
}
},
"ignore_above" : 30000
}
}
},
"settings" : {
"index" : {
"max_ngram_diff" : "49",
"number_of_shards" : "1",
"provided_name" : "posts_development_20200709141330421",
"max_shingle_diff" : "4",
"creation_date" : "1594271610438",
"analysis" : {
"filter" : {
"searchkick_suggest_shingle" : {
"max_shingle_size" : "5",
"type" : "shingle"
},
"searchkick_edge_ngram" : {
"type" : "edge_ngram",
"min_gram" : "1",
"max_gram" : "50"
},
"searchkick_index_shingle" : {
"token_separator" : "",
"type" : "shingle"
},
"searchkick_search_shingle" : {
"token_separator" : "",
"output_unigrams_if_no_shingles" : "true",
"output_unigrams" : "false",
"type" : "shingle"
},
"searchkick_ngram" : {
"type" : "ngram",
"min_gram" : "1",
"max_gram" : "50"
}
},
"analyzer" : {
"searchkick_word_start_index" : {
"filter" : [
"lowercase",
"asciifolding",
"searchkick_edge_ngram"
],
"type" : "custom",
"tokenizer" : "standard"
},
"searchkick_keyword" : {
"filter" : [
"lowercase"
],
"type" : "custom",
"tokenizer" : "keyword"
},
"searchkick_text_end_index" : {
"filter" : [
"lowercase",
"asciifolding",
"reverse",
"searchkick_edge_ngram",
"reverse"
],
"type" : "custom",
"tokenizer" : "keyword"
},
"searchkick_search2" : {
"type" : "kuromoji"
},
"searchkick_word_middle_index" : {
"filter" : [
"lowercase",
"asciifolding",
"searchkick_ngram"
],
"type" : "custom",
"tokenizer" : "standard"
},
"searchkick_search" : {
"type" : "kuromoji"
},
"searchkick_text_start_index" : {
"filter" : [
"lowercase",
"asciifolding",
"searchkick_edge_ngram"
],
"type" : "custom",
"tokenizer" : "keyword"
},
"searchkick_word_end_index" : {
"filter" : [
"lowercase",
"asciifolding",
"reverse",
"searchkick_edge_ngram",
"reverse"
],
"type" : "custom",
"tokenizer" : "standard"
},
"searchkick_word_search" : {
"filter" : [
"lowercase",
"asciifolding"
],
"type" : "custom",
"tokenizer" : "standard"
},
"searchkick_autocomplete_search" : {
"filter" : [
"lowercase",
"asciifolding"
],
"type" : "custom",
"tokenizer" : "keyword"
},
"searchkick_suggest_index" : {
"filter" : [
"lowercase",
"asciifolding",
"searchkick_suggest_shingle"
],
"type" : "custom",
"tokenizer" : "standard"
},
"searchkick_text_middle_index" : {
"filter" : [
"lowercase",
"asciifolding",
"searchkick_ngram"
],
"type" : "custom",
"tokenizer" : "keyword"
},
"searchkick_index" : {
"type" : "kuromoji"
}
},
"char_filter" : {
"ampersand" : {
"type" : "mapping",
"mappings" : [
"&=> and "
]
}
}
},
"number_of_replicas" : "1",
"uuid" : "irv_ZciHQuOZc_QndmsG1Q",
"version" : {
"created" : "7080099"
}
}
}
}
}
Railsのコード
class Post < ApplicationRecord
has_many :post_category_relations
has_many :categories, through: :post_category_relations
searchkick language: "japanese"
def search_data
{
name: name,
description: description,
category_name: categories.map(&:name)
}
end
end
上記でlanguage: "japanese"
を付与してPost.reindex
するだけで、analyzersearchkick_index
とsearchkick_search
のtype
がkuromojiに指定されるようです。
class Category < ApplicationRecord
has_many :post_category_relations
has_many :posts, through: :post_category_relations
has_ancestry
after_commit :reindex_post
def reindex_post
post.reindex
end
end
def index
@posts = self.query
end
private
def query
if params[:q]
Post.search params[:q], fields: [:name, :description, :category_name]
else
Post.all
end
end
試したこと
kibanaコンソールでの実験
GET /posts_development/_search
{
"query": {
"multi_match": {
"fields": [ "name", "description", "category_name"],
"query": "日本の絶景",
"analyzer": "searchkick_index" // ←ここを削除するとヒットしない
}
}
}
"analyzer": "searchkick_index"
を削除するとヒットしません。しかしfieldsのcategory_name
をcategory_name.analyzed
とするとヒットします。
GET /posts_development/_analyze
{
"text" : "日本の絶景"
}
→「日」「本」「の」「絶」「景」の5トークン
GET /posts_development/_analyze
{
"analyzer": "searchkick_index",
"text" : "日本の絶景"
}
→「日本」「絶景」の2トークン
GET /posts_development/_analyze
{
"tokenizer": "kuromoji_tokenizer",
"text" : "日本の絶景"
}
→「日本」「の」「絶景」の3トークン
補足情報(FW/ツールのバージョンなど)
- Ruby 2.7.1
- Rails 6.0
- elasticsearch-oss 7.8.0 (/usr/local/bin/elasticsearch)
- kibana-oss 7.8.0 (/usr/local/bin/kibana)
- kuromoji 7.8.0
- searchkick 4.4.1
- ancestry 3.0.7
teratailでも質問したのですが、ここを教えていただき質問させていただきました。1日近くググれども実験せども正直お手上げ状態で、お助けいただけますと幸いです🙇♀️