ユアマイスター株式会社エンジニアブログ

ユアマイスター株式会社のエンジニアが日々徒然。

検索改善 Elasticsearchでハマった沼

ユアマイスターエンジニアです。

弊社サービス「あなたのマイスター」では、モリモリとサービス改善を実施中です。

http://yourmystar.jp/

ある日、社内で誰かがつぶやいたんですよ。

「検索、遅くね?」

知っていた、知っていましたとも!

「なんかAm◯zonみたいなキーワード検索とかできないのかな」

エンジニア以外にはわからないかもしれないけどけっこう大変なんだよそれ!

しかし、きっとこの改善を達成すればお客様も喜んでくれるはず…

その思いからなんやかんやあって検索を全文検索エンジンであるElasticsearchへ切り替えました。

情熱って大事。

第一の沼

とりあえずCakePHPからも公式でプラグインは出ているみたいだし、楽勝だろうという思いでいたのですが…

ElasticSearch

どうもこの方法でインストールするプラグインは導入時の最新バージョンのElasticsearchに対応していない様子。

結果として「全件取得以外は何をやってもエラーになる」という悲しみに包まれました。

これに気付くのに2日かかったよ…なにやってもダメなんだもん…

というわけで公式リファレンスを読みながら

www.elastic.co

なんとか自前のコンポーネントを作りましたとさ。めでたしめでたし。

第二の沼

Elasticsearchって結局のところJSONでデータを出し入れするわけですが

{
  "users" :
    [
      {
        "id" : 1,
        "name": "ゆあまい すたろう",
        "tel": [
                  {"number": 09000000001},
                  {"number": 09000000002}
                ]
      },
      {
        "id" : 2,
        "name": "ゆあまい すたこ",
        "tel": [
                  {"number": 09000000003},
                  {"number": 09000000004}
                ]
      }
  ]
}

こういうデータの「電話番号だけを更新したい、ってことあるじゃないですか。

例えば「09000000004」「09000000005」「09000000006」の3つに強制的に変更するとします。

つまり、配列内の要素のみをUPDATEしたい場合ですね。

この際に、ハマりました。

www.elastic.co

Elasticsearch 2.x で複数のドキュメントにUPDATE文のようなもの実行する – wired-world

こんな感じで書いてあるもんだから

{
  "script": {
    "inline": "ctx._source.users.tel = 
        [
         {\"number\" : 09000000004},
         {\"number\" : 09000000005},
         {\"number\" : 09000000006}
        ]"
  }
}

ダメでした…

正解は

POST XXX/_update_by_query
{
  "script": {
    "inline": "ctx._source.users.tel = 
      [
        [\"number\" : 09000000004],
        [\"number\" : 09000000005],
        [\"number\" : 09000000006]"
      ]
  }
}

おいおい…配列内のオブジェクトはカギカッコでくくるんですか…そうですか…

公式リファレンスをざっと読んだ限りは見当たらなかったです。

第三の沼

OR検索をするときには should 句を使うんですが、

www.elastic.co

このときには minimum_should_match も同時に設定してあげなければなりません。

「最低◯個は合致しないとダメだよー」的な感じのパラメータですね。

通常のOR検索の場合は "minimum_should_match" : 1 となります。

(1個以上該当すればいいので)

しかしながら!shouldの条件を一つも指定せずに "minimum_should_match" : 1 とした場合どうなるか…

エラーにはならず、1件も取得できません。

気をつけましょう。私はボスに坊主にされるところでした。

実際の改善結果

速度的には50〜100倍ほどの速度になりました。

界王拳もびっくりなインフレ具合です。

まだまだチューニングする余地はたくさんあるので、今後も技術を通してお客様に価値を提供できたら良いな!と考えています。