# Searchkick経由でのkuromojiが機能しない

**URL:** <https://discuss.elastic.co/t/searchkick-kuromoji/240493>\
**Category:** 日本語による質問・議論はこちら\
**Created:** [July 9, 2020, 8:31am UTC](https://discuss.elastic.co/t/searchkick-kuromoji/240493 "2020-07-09T08:31:18Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![maztak](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/maztak/32/71856_2.png) [@maztak](https://discuss.elastic.co/u/maztak)\
**Post date:** [July 9, 2020, 8:31am UTC](https://discuss.elastic.co/t/searchkick-kuromoji/240493/1 "2020-07-09T08:31:18Z")

</div>

初めてここで質問させていただきます 🙇‍♂️

現在、RailsのGemであるSearchkick経由でkuromojiプラグインを使っているのですが、Kibanaコンソールではちゃんと形態素解析され目的の検索結果がでるのに、localhost:3000で実際に検索するとヒットしません。

### 前提・実現したいこと

各カテゴリーで良質な情報を提供するサイトのデータベースを作っています。Railsで「[searchkick](https://github.com/ankane/searchkick)」と「kuromoji」 を使って、投稿（`Post`）の検索機能を実装しているところです。

以下のER図のように、PostとCategoryは多対多で、かつCategoryは[Ancestry](https://github.com/stefankroes/ancestry)を使って多階層化されています。

例えばnameが「世界名所100選」であるPostが、Category「絶景」をリレーションとして持っているとき、「日本の絶景」と検索してもヒットするようにしたいです。

 ![データベース ER 図](https://us1.discourse-cdn.com/elastic/original/3X/c/3/c34634357dec56be543d1cd33a96b2e57bef4467.png)

### 発生している問題・エラーメッセージ

kibanaコンソールでは以下のようにGETすると上手くヒットするのですが、実際の（Rails s で立ち上げたlocalhost:3000にて）検索窓に「日本の絶景」と打ち込んでも何もヒットしません。

```auto
GET /posts_development/_search
{
  "query": {
    "multi_match": {
      "fields": ["name", "description", "category_name"],
      "query": "日本の絶景",
      "analyzer": "searchkick_index"
    }
  }
}

```

### 該当のソースコード

#### インデックスの設定

```auto
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のコード

```auto
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`するだけで、analyzer`searchkick_index`と`searchkick_search`の`type`がkuromojiに指定されるようです。

```auto
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

```

```auto
  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コンソールでの実験

```auto
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`とするとヒットします。

```auto
GET /posts_development/_analyze
{
  "text" : "日本の絶景"
}
→「日」「本」「の」「絶」「景」の5トークン

```

```auto
GET /posts_development/_analyze
{
  "analyzer": "searchkick_index",
  "text" : "日本の絶景"
}
→「日本」「絶景」の2トークン

```

```auto
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でも質問した](https://teratail.com/questions/276328)のですが、ここを教えていただき質問させていただきました。1日近くググれども実験せども正直お手上げ状態で、お助けいただけますと幸いです🙇‍♀️

---

<div class="post-metadata">

**Author:** ![tsgkdt](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/tsgkdt/32/39151_2.png) [@tsgkdt](https://discuss.elastic.co/u/tsgkdt)\
**Post date:** [July 9, 2020, 12:51pm UTC](https://discuss.elastic.co/t/searchkick-kuromoji/240493/2 "2020-07-09T12:51:29Z")

</div>

まったくSearchkickを存じ上げないので、的外れかもしれませんが・・・

Kibanaで検索できることが確認できているという状態なので、Searchkick経由でなぜ検索できないのか、デバッグログを出してみてうまくいくクエリと比較するのはどうでしょうか。

> **[GitHub - ankane/searchkick: Intelligent search made easy](https://github.com/ankane/searchkick#debugging-queries)**
>
> Intelligent search made easy. Contribute to ankane/searchkick development by creating an account on GitHub.

また、just ideaですが、queryingの箇所に以下のように記載があり、何もないとandと書いてあります。「日本の絶景」だと「日本 & 絶景」となり、「絶景」だけを含むカテゴリ名がヒットしないのでは？と。とりあえずorをつけてみるのはどうでしょう。

> Product.search "fresh honey" # fresh AND honey  
> Product.search "fresh honey", operator: "or" # fresh OR honey

multi\_matchの方は、デフォルトでoperatorがorなのでもしかしたら？と思った次第です。

---

<div class="post-metadata">

**Author:** ![maztak](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/maztak/32/71856_2.png) [@maztak](https://discuss.elastic.co/u/maztak)\
**Post date:** [July 9, 2020, 1:35pm UTC](https://discuss.elastic.co/t/searchkick-kuromoji/240493/3 "2020-07-09T13:35:44Z")

</div>

おおおおお、このような長い質問にご回答ありがとうございます😭神です、ほんと。

そしてorめちゃめちゃ怪しいですね！おそらくビンゴだと思います😅

私もログを見ようとしてさらに苦戦してたとこですが、searchkick側にdebugの設定があったとは…！

感謝感激です☺️

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [August 6, 2020, 1:35pm UTC](https://discuss.elastic.co/t/searchkick-kuromoji/240493/4 "2020-08-06T13:35:47Z")

</div>

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.
