質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Elasticsearch

Elasticsearchは、クラウド向けに構築された、RESTful な API を提供する分散型のサーチエンジンアプリケーションです。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

1回答

1264閲覧

Searchkickでkuromojiによる検索ができない

maztak

総合スコア61

Elasticsearch

Elasticsearchは、クラウド向けに構築された、RESTful な API を提供する分散型のサーチエンジンアプリケーションです。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

0クリップ

投稿2020/07/09 07:30

編集2020/07/09 08:13

前提・実現したいこと

各カテゴリーで良質な情報を提供するサイトのデータベースを作っています。RailsでElastricsearchを簡単に使えるようにしてくれるGem「searchkick」と、日本語形態素解析器である「kuromoji」 を使って、投稿Postを検索できるようにしたいです。

イメージ説明

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" } } }

該当のソースコード

インデックスの設定

console

1GET /posts_development?pretty 2 3返り値↓ 4 5{ 6 "posts_development_20200709141330421" : { 7 "aliases" : { 8 "posts_development" : { } 9 }, 10 "mappings" : { 11 "dynamic_templates" : [ 12 { 13 "string_template" : { 14 "match" : "*", 15 "match_mapping_type" : "string", 16 "mapping" : { 17 "fields" : { 18 "analyzed" : { 19 "analyzer" : "searchkick_index", 20 "index" : true, 21 "type" : "text" 22 } 23 }, 24 "ignore_above" : 30000, 25 "type" : "keyword" 26 } 27 } 28 } 29 ], 30 "properties" : { 31 "category_name" : { 32 "type" : "keyword", 33 "fields" : { 34 "analyzed" : { 35 "type" : "text", 36 "analyzer" : "searchkick_index" 37 } 38 }, 39 "ignore_above" : 30000 40 }, 41 "description" : { 42 "type" : "keyword", 43 "fields" : { 44 "analyzed" : { 45 "type" : "text", 46 "analyzer" : "searchkick_index" 47 } 48 }, 49 "ignore_above" : 30000 50 }, 51 "name" : { 52 "type" : "keyword", 53 "fields" : { 54 "analyzed" : { 55 "type" : "text", 56 "analyzer" : "searchkick_index" 57 } 58 }, 59 "ignore_above" : 30000 60 } 61 } 62 }, 63 "settings" : { 64 "index" : { 65 "max_ngram_diff" : "49", 66 "number_of_shards" : "1", 67 "provided_name" : "posts_development_20200709141330421", 68 "max_shingle_diff" : "4", 69 "creation_date" : "1594271610438", 70 "analysis" : { 71 "filter" : { 72 "searchkick_suggest_shingle" : { 73 "max_shingle_size" : "5", 74 "type" : "shingle" 75 }, 76 "searchkick_edge_ngram" : { 77 "type" : "edge_ngram", 78 "min_gram" : "1", 79 "max_gram" : "50" 80 }, 81 "searchkick_index_shingle" : { 82 "token_separator" : "", 83 "type" : "shingle" 84 }, 85 "searchkick_search_shingle" : { 86 "token_separator" : "", 87 "output_unigrams_if_no_shingles" : "true", 88 "output_unigrams" : "false", 89 "type" : "shingle" 90 }, 91 "searchkick_ngram" : { 92 "type" : "ngram", 93 "min_gram" : "1", 94 "max_gram" : "50" 95 } 96 }, 97 "analyzer" : { 98 "searchkick_word_start_index" : { 99 "filter" : [ 100 "lowercase", 101 "asciifolding", 102 "searchkick_edge_ngram" 103 ], 104 "type" : "custom", 105 "tokenizer" : "standard" 106 }, 107 "searchkick_keyword" : { 108 "filter" : [ 109 "lowercase" 110 ], 111 "type" : "custom", 112 "tokenizer" : "keyword" 113 }, 114 "searchkick_text_end_index" : { 115 "filter" : [ 116 "lowercase", 117 "asciifolding", 118 "reverse", 119 "searchkick_edge_ngram", 120 "reverse" 121 ], 122 "type" : "custom", 123 "tokenizer" : "keyword" 124 }, 125 "searchkick_search2" : { 126 "type" : "kuromoji" 127 }, 128 "searchkick_word_middle_index" : { 129 "filter" : [ 130 "lowercase", 131 "asciifolding", 132 "searchkick_ngram" 133 ], 134 "type" : "custom", 135 "tokenizer" : "standard" 136 }, 137 "searchkick_search" : { 138 "type" : "kuromoji" 139 }, 140 "searchkick_text_start_index" : { 141 "filter" : [ 142 "lowercase", 143 "asciifolding", 144 "searchkick_edge_ngram" 145 ], 146 "type" : "custom", 147 "tokenizer" : "keyword" 148 }, 149 "searchkick_word_end_index" : { 150 "filter" : [ 151 "lowercase", 152 "asciifolding", 153 "reverse", 154 "searchkick_edge_ngram", 155 "reverse" 156 ], 157 "type" : "custom", 158 "tokenizer" : "standard" 159 }, 160 "searchkick_word_search" : { 161 "filter" : [ 162 "lowercase", 163 "asciifolding" 164 ], 165 "type" : "custom", 166 "tokenizer" : "standard" 167 }, 168 "searchkick_autocomplete_search" : { 169 "filter" : [ 170 "lowercase", 171 "asciifolding" 172 ], 173 "type" : "custom", 174 "tokenizer" : "keyword" 175 }, 176 "searchkick_suggest_index" : { 177 "filter" : [ 178 "lowercase", 179 "asciifolding", 180 "searchkick_suggest_shingle" 181 ], 182 "type" : "custom", 183 "tokenizer" : "standard" 184 }, 185 "searchkick_text_middle_index" : { 186 "filter" : [ 187 "lowercase", 188 "asciifolding", 189 "searchkick_ngram" 190 ], 191 "type" : "custom", 192 "tokenizer" : "keyword" 193 }, 194 "searchkick_index" : { 195 "type" : "kuromoji" 196 } 197 }, 198 "char_filter" : { 199 "ampersand" : { 200 "type" : "mapping", 201 "mappings" : [ 202 "&=> and " 203 ] 204 } 205 } 206 }, 207 "number_of_replicas" : "1", 208 "uuid" : "irv_ZciHQuOZc_QndmsG1Q", 209 "version" : { 210 "created" : "7080099" 211 } 212 } 213 } 214 } 215} 216

Railsのコード

post.rb

1class Post < ApplicationRecord 2 has_many :post_category_relations 3 has_many :categories, through: :post_category_relations 4 5 searchkick language: "japanese" 6 7 def search_data 8 { 9 name: name, 10 description: description, 11 category_name: categories.map(&:name) 12 } 13 end 14end

上記でlanguage: "japanese"を付与してPost.reindexするだけで、analyzersearchkick_indexsearchkick_searchtypeがkuromojiに指定されるようです。

category.rb

1class Category < ApplicationRecord 2 has_many :post_category_relations 3 has_many :posts, through: :post_category_relations 4 has_ancestry 5 6 after_commit :reindex_post 7 8 def reindex_post 9 post.reindex 10 end 11end

post_controller.rb

1 def index 2 @posts = self.query 3 end 4 5 private 6 def query 7 if params[:q] 8 Post.search params[:q], fields: [:name, :description, :category_name] 9 else 10 Post.all 11 end 12 end

試したこと

kibanaコンソールでの実験

GET /posts_development/_search { "query": { "multi_match": { "fields": [ "name", "description", "category_name"], "query": "日本の絶景", "analyzer": "searchkick_index" // ←ここを削除するとヒットしない } } }

"analyzer": "searchkick_index"を削除するとヒットしません。しかしfieldsのcategory_namecategory_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トークン

他のインデックスの削除

これ以外のインデックスは.kibanaというのがあるだけ(もとからあって消してもKibanaにより自動生成される?)

Post.reindex をする前にRailsコンソールを再起動しなおす

これにより再起動しないとMappingなどの情報が反映されないことがわかりました。

Post.rb にマッピングや設定情報を手動で追加

KibanaコンソールでGET /posts_development/_mapping?prettyをしたときの返り値をもとに、以下のようにsearch_analyzerを明示的に設定してみましたが変わらず。

Post.rb

1searchkick language: "japanese", merge_mappings: true, 2 mappings: { 3 properties: { 4 category_name: { 5 type: "keyword", 6 fields: { 7 analyzed: { 8 type: "text", 9 analyzer: "searchkick_index", 10 search_analyzer: "searchkick_search" 11 } 12 }, 13 ignore_above: 30000 14 } 15 } 16 }

補足情報(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

1日近くググれども実験せども正直お手上げ状態で、お助けいただけますと幸いです????‍♀️

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

Elasticsearchのフォーラムで教えていただき、SearchkickがデフォルトではAND検索になるので「日本 AND 絶景」というクエリに変換されてしたのでした!operator: "or"を付与すれば解決です。

Post.search params[:q], fields: [:name, :description, :category_name], operator: "or"

「日本の絶景」以外のクエリではなんか上手く言ってそうな気配もあったので、色んなクエリで試すことが大事なのかなと。

投稿2020/07/09 23:23

maztak

総合スコア61

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問