🔎

Meilisearch使ってみる 0.27.2編

2022/06/14に公開

0.27で日本語がサポートされたということで、改めて色々やってみようと思い、メモを残します。

環境

  • Meilisearch: 0.27.2

バージョンを上げる

前回やった時は 0.24系だったため、まずはバージョンをあげます。

 services:
   meilisearch:
     container_name: meilisearch
-    image: getmeili/meilisearch:v0.24.0
+    image: getmeili/meilisearch:v0.27.2
     volumes:
-      - meili-data:/data.ms
+      - meili-data:/meili_data/data.ms
     environment:
       MEILI_MASTER_KEY: api-key
     ports:

起動してみます

docker-compose up meilisearch
WARNING: Native build is an experimental feature and could change at any time
Creating meilisearch ... done
Attaching to meilisearch
meilisearch       | Error: Meilisearch (v0.27.2) failed to infer the version of the database. Please consider using a dump to load your data.
meilisearch exited with code 1

怒られました。
Meilisearchはマイナーバージョン変わると旧バージョンのデータをそのまま引き継げないんですよね。
運用時は結構面倒ですね。

Update to the latest Meilisearch version | Meilisearch Documentation v0.27

ここに書かれていますが、dumpしてimportする、っていう手順が必要です。

今回は面倒なので、一回Volumeを削除することでデータを消して立ち上げ直しました

Indexing

まずは普通に1ドキュメントずつ入れてみます

require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'
  gem "meilisearch"
  gem "gimei"
  gem "parallel"
end

require "meilisearch"
require "gimei"
require "parallel"

MEILI_URL = "http://localhost:7700"

def documents(range)
  puts "-" * 100
  puts "generate documents"
  puts range
  puts "start #{Time.now}"
  range.map{|i|
    director = Gimei.name
    {
      id: i,
      title: Gimei.address.kanji,
      actors: 10.times.map { Gimei.name.kanji },
      director: director.kanji,
      director_kana: director.hiragana,
    }
  }.tap{
    puts "end #{Time.now}"
    puts "-" * 100
  }
end

index = MeiliSearch::Client.new(MEILI_URL, "api-key")
          .index("movies")

Parallel.each(documents(0...10000)) { |document|
  index.add_documents(document)
}

indexingの進捗を見てみます

curl -s -H "Authorization: Bearer api-key" http://localhost:7700/indexes/movies/tasks | jq '.results[].status' | sort | uniq -c
   7625 "enqueued"
      1 "processing"
   2374 "succeeded"

processingが1です。
これとても時間がかかります。

Auto Batching

ここで、登場するのが 0.26 で追加されたexperimental featureの AutoBatching です。

Auto-batching | Meilisearch Documentation v0.27
※0.27.2時点では実験的な機能であるため、環境変数から設定できません。
※実験的な機能なので、-h しても表示されません。

docker-compose.ymlでmeilisearchの起動オプションを入れます

docker-compose.yml
     image: getmeili/meilisearch:v0.27.2
     volumes:
       - meili-data:/meili_data/data.ms
+    command: meilisearch --enable-auto-batching
     environment:
       MEILI_MASTER_KEY: api-key
     ports:

再起動して、tasksを見てみます

curl -s -H "Authorization: Bearer api-key" http://localhost:7700/indexes/movies/tasks | jq '.results[].status' | sort | uniq -c
    979 "enqueued"
   1085 "processing"
  21045 "succeeded"

"processing" の数が増えましたね。
自動的にバッチ処理にしてくれています。
これで劇的にindexingが速くなりました。

require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'
  gem "meilisearch"
end

require "meilisearch"

MEILI_URL = "http://localhost:7700"

@index = MeiliSearch::Client.new(MEILI_URL, "api-key")
  .index("movies")

def search(query)
  puts "-" * 100
  puts "QUERY: #{query}"
  pp @index.search(
    query,
    {
      attributesToHighlight: ['*'],
      limit: 5,
    },
  )
end

search("もとゆき")

もとゆき で検索してみる

----------------------------------------------------------------------------------------------------
QUERY: もとゆき
{"hits"=>
  [{"id"=>920,
    "title"=>"埼玉県曽於郡大崎町大蔵",
    "actors"=>["望月 泰秀", "栗田 刀万", "馬場 拓実", "中井 三葉", "桑原 章", "大川 志絵", "石田 里弥", "宮本 純絵", "宮田 亨典", "三木 璃空"],
    "director"=>"藤本 有貴",
    "director_kana"=>"ふじもと ゆき",
    "_formatted"=>{"id"=>"920", "title"=>"埼玉県曽於郡大崎町大蔵", "actors"=>["望月 泰秀", "栗田 刀万", "馬場 拓実", "中井 三葉", "桑原 章", "大川 志絵", "石田 里弥", "宮本 純絵", "宮田 亨典", "三木 璃空"], "director"=>"藤本 有貴", "director_kana"=>"ふじ<em>もと</em> <em>ゆき</em>"}},
   {"id"=>1638,
    "title"=>"京都府神戸市兵庫区二見町",
    "actors"=>["永田 馨喜", "瀬戸 和之", "竹中 藍澄", "南 漣", "高井 笑歌", "今村 歩", "大西 郁文", "入江 佳乃", "千葉 風菜", "大田 夢架"],
    "director"=>"吉本 夕岐",
    "director_kana"=>"よしもと ゆき",
    "_formatted"=>{"id"=>"1638", "title"=>"京都府神戸市兵庫区二見町", "actors"=>["永田 馨喜", "瀬戸 和之", "竹中 藍澄", "南 漣", "高井 笑歌", "今村 歩", "大西 郁文", "入江 佳乃", "千葉 風菜", "大田 夢架"], "director"=>"吉本 夕岐", "director_kana"=>"よし<em>もと</em> <em>ゆき</em>"}},
   {"id"=>4872,
    "title"=>"岐阜県山梨市割田",
    "actors"=>["堀江 恵海", "西野 政寛", "今井 志優", "菅原 未園", "市川 久見", "大島 凌馬", "八木 琉", "藤沢 陽翔", "小野 光景", "永野 蛍里"],
    "director"=>"森本 夕稀",
    "director_kana"=>"もりもと ゆき",
    "_formatted"=>{"id"=>"4872", "title"=>"岐阜県山梨市割田", "actors"=>["堀江 恵海", "西野 政寛", "今井 志優", "菅原 未園", "市川 久見", "大島 凌馬", "八木 琉", "藤沢 陽翔", "小野 光景", "永野 蛍里"], "director"=>"森本 夕稀", "director_kana"=>"もり<em>もと</em> <em>ゆき</em>"}},
   {"id"=>4975,
    "title"=>"鹿児島県京都市下京区春日川中",
    "actors"=>["塚田 豊和", "竹内 正一", "原口 健臣", "松村 広夢", "平川 彩織", "杉浦 圭輔", "川本 優舞", "寺田 貴弘", "高野 祐生", "荻野 碧泉"],
    "director"=>"竹本 倖歩",
    "director_kana"=>"たけもと ゆきほ",
    "_formatted"=>{"id"=>"4975", "title"=>"鹿児島県京都市下京区春日川中", "actors"=>["塚田 豊和", "竹内 正一", "原口 健臣", "松村 広夢", "平川 彩織", "杉浦 圭輔", "川本 優舞", "寺田 貴弘", "高野 祐生", "荻野 碧泉"], "director"=>"竹本 倖歩", "director_kana"=>"たけ<em>もと</em> <em>ゆき</em>ほ"}},
   {"id"=>8195,
    "title"=>"長野県気仙郡住田町清水村松地先新田",
    "actors"=>["吉本 広佳", "岡野 絵舞", "石塚 雅章", "丸山 七巳", "本田 遙斗", "白井 仁孝", "泉 末由", "天野 優志", "日野 竜二", "徳田 紗幸"],
    "director"=>"加藤 基之",
    "director_kana"=>"かとう もとゆき",
    "_formatted"=>{"id"=>"8195", "title"=>"長野県気仙郡住田町清水村松地先新田", "actors"=>["吉本 広佳", "岡野 絵舞", "石塚 雅章", "丸山 七巳", "本田 遙斗", "白井 仁孝", "泉 末由", "天野 優志", "日野 竜二", "徳田 紗幸"], "director"=>"加藤 基之", "director_kana"=>"かとう <em>もと</em><em>ゆき</em>"}}],
 "nbHits"=>9,
 "exhaustiveNbHits"=>false,
 "query"=>"もとゆき",
 "limit"=>5,
 "offset"=>0,
 "processingTimeMs"=>3}

かとう もとゆき よりも ふじもと ゆきもと ゆき がマッチ度が高いらしいですね。
おそらく
もとゆき -> もと ゆき
と形態素解析されているのではないかと。

https://github.com/meilisearch/charabia/blob/1dcaf3cd872d36ad66be41368ab2a97892980a90/Cargo.toml#L23
MeilisearchはLinderaのipadicを使っているっぽいので、mecabのipadicで形態素解析してみると

echo もとゆき | mecab
もと    接頭詞,名詞接続,*,*,*,*,もと,モト,モト
ゆき    名詞,一般,*,*,*,*,ゆき,ユキ,ユキ
EOS

こうなるので、おそらくそういうことかなぁ?と。

上田の口 で検索してみる

----------------------------------------------------------------------------------------------------
QUERY: 上田の口
{"hits"=>
  [{"id"=>2293,
    "title"=>"佐賀県三条市上田の口",
    "actors"=>["野口 林", "長田 稜真", "三宅 仙莉", "萩原 窓楓", "天野 庸孝", "黒川 翠音", "杉山 夏輝", "平松 晶野", "三上 夏初", "石崎 英治"],
    "director"=>"平野 礼詠",
    "director_kana"=>"ひらの あやえ",
    "_formatted"=>{"id"=>"2293", "title"=>"佐賀県三条市<em>上田の口</em>", "actors"=>["野口 林", "長<em>田</em> 稜真", "三宅 仙莉", "萩原 窓楓", "天野 庸孝", "黒川 翠音", "杉山 夏輝", "平松 晶野", "三上 夏初", "石崎 英治"], "director"=>"平野 礼詠", "director_kana"=>"ひら<em>の</em> あやえ"}},
   {"id"=>4181,
    "title"=>"青森県筑後市上田の口",
    "actors"=>["岩崎 来知", "藤岡 詩由", "井上 大翔", "関口 葉奈", "畑中 貴優", "松山 柊太", "斎藤 桃衣", "高松 千皓", "大西 糸保", "森川 采紗"],
    "director"=>"松田 誓奏",
    "director_kana"=>"まつだ せな",
    "_formatted"=>{"id"=>"4181", "title"=>"青森県筑後市<em>上田の口</em>", "actors"=>["岩崎 来知", "藤岡 詩由", "井上 大翔", "関口 葉奈", "畑中 貴優", "松山 柊太", "斎藤 桃衣", "高松 千皓", "大西 糸保", "森川 采紗"], "director"=>"松田 誓奏", "director_kana"=>"まつだ せな"}},
   {"id"=>8832,
    "title"=>"石川県豊前市上田の口",
    "actors"=>["片山 樹奈", "佐々木 文歌", "石山 晶霞", "三浦 明弘", "渡部 喜造", "緒方 清麗", "内藤 爽", "池上 麻代", "島村 岳人", "宮下 龍樹"],
    "director"=>"新井 叶望",
    "director_kana"=>"あらい かなみ",
    "_formatted"=>{"id"=>"8832", "title"=>"石川県豊前市<em>上田の口</em>", "actors"=>["片山 樹奈", "佐々木 文歌", "石山 晶霞", "三浦 明弘", "渡部 喜造", "緒方 清麗", "内藤 爽", "池上 麻代", "島村 岳人", "宮下 龍樹"], "director"=>"新井 叶望", "director_kana"=>"あらい かなみ"}},
   {"id"=>9617,
    "title"=>"岡山県気仙沼市上田の口",
    "actors"=>["谷口 哲哉", "白川 光彩", "秋元 貴弘", "松永 佳果", "園田 遼遥", "出口 善高", "大山 悠哉", "畑中 里樹", "渡部 一俊", "藤川 美夜"],
    "director"=>"高田 家康",
    "director_kana"=>"たかだ いえやす",
    "_formatted"=>{"id"=>"9617", "title"=>"岡山県気仙沼市<em>上田の口</em>", "actors"=>["谷口 哲哉", "白川 光彩", "秋元 貴弘", "松永 佳果", "園田 遼遥", "出口 善高", "大山 悠哉", "畑中 里樹", "渡部 一俊", "藤川 美夜"], "director"=>"高田 家康", "director_kana"=>"たかだ いえやす"}},
   {"id"=>4809,
    "title"=>"秋田県たつの市上田の口",
    "actors"=>["村上 弘昭", "神田 瑞麗", "根本 友結", "浜口 渉", "小島 峰帆", "藤岡 水恵", "増田 芽生", "中田 望", "山川 浩逸", "亀井 昌枝"],
    "director"=>"篠原 郷",
    "director_kana"=>"しのはら さと",
    "_formatted"=>{"id"=>"4809", "title"=>"秋田県たつ<em>の</em>市<em>上田の口</em>", "actors"=>["村上 弘昭", "神田 瑞麗", "根本 友結", "浜<em>口</em> 渉", "小島 峰帆", "藤岡 水恵", "増<em>田</em> 芽生", "中<em>田</em> 望", "山川 浩逸", "亀井 昌枝"], "director"=>"篠原 郷", "director_kana"=>"しのはら さと"}}],
 "nbHits"=>13,
 "exhaustiveNbHits"=>false,
 "query"=>"上田の口",
 "limit"=>5,
 "offset"=>0,
 "processingTimeMs"=>3}

"田の口" で検索すると

----------------------------------------------------------------------------------------------------
QUERY: 田の口
{"hits"=>[], "nbHits"=>0, "exhaustiveNbHits"=>false, "query"=>"田の口", "limit"=>5, "offset"=>0, "processingTimeMs"=>0}

なにもヒットしない

echo "田の口" | mecab
田の口  名詞,固有名詞,地域,一般,*,*,田の口,タノクチ,タノクチ
EOS

❯ echo "上田の口" | mecab
上田    名詞,固有名詞,人名,姓,*,*,上田,ウエダ,ウエダ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
口      名詞,一般,*,*,*,*,口,クチ,クチ
EOS

形態素解析結果を見ると納得。

(これは検索の用途によっては形態素じゃなくてn-gramになってくれたほうが嬉しい場合もあるかもしれない)

Json型のフィールドがある場合の検索結果

require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'
  gem "meilisearch"
  gem "gimei"
  gem "parallel"
end

require "meilisearch"
require "gimei"
require "parallel"

MEILI_URL = "http://localhost:7700"

def documents(range)
  puts "-" * 100
  puts "generate documents"
  puts range
  puts "start\t#{Time.now}"
  Parallel.map(range) {|i|
    director = Gimei.name
    {
      id: i,
      title: Gimei.address.kanji,
      director: director.kanji,
      director_kana: director.hiragana,
      json_field: {
        hoge_id: "hogehoge",
        foo_id: (0..10000).to_a.sample,
        name_1: Gimei.name.kanji,
        name_2: Gimei.name.kanji,
        name_3: Gimei.name.hiragana,
      },
    }
  }.tap{
    puts "end\t#{Time.now}"
    puts "-" * 100
  }
end

index = MeiliSearch::Client.new(MEILI_URL, "api-key", max_retries: 10, timeout: 30)
          .index("movies")

index.delete

Parallel.each(documents(0...500000).tap{|x| pp x.first; pp x.last}) { |document|
  begin
    index.add_documents(document, "id")
  rescue => e
    puts "=" * 100
    pp document
    pp e
  end
}

50万件のデータを入れてみました。

hogehoge で検索してみる

hoge_id の value にあたる値で検索してみます。

(limit: 3)

----------------------------------------------------------------------------------------------------
QUERY: hogehoge
{"hits"=>
  [{"id"=>0,
    "title"=>"山口県雨竜郡雨竜町松山",
    "director"=>"清水 規郎",
    "director_kana"=>"しみず のりお",
    "json_field"=>{"hoge_id"=>"hogehoge", "foo_id"=>1655, "name_1"=>"工藤 玲有", "name_2"=>"三浦 秋音", "name_3"=>"つじ さち"},
    "_formatted"=>{"id"=>"0", "title"=>"山口県雨竜郡雨竜町松山", "director"=>"清水 規郎", "director_kana"=>"しみず のりお", "json_field"=>{"hoge_id"=>"<em>hogehoge</em>", "foo_id"=>"1655", "name_1"=>"工藤 玲有", "name_2"=>"三浦 秋音", "name_3"=>"つじ さち"}}},
   {"id"=>1,
    "title"=>"神奈川県下北郡大間町仁井田潟中町",
    "director"=>"浜田 憲一",
    "director_kana"=>"はまだ けんいち",
    "json_field"=>{"hoge_id"=>"hogehoge", "foo_id"=>7514, "name_1"=>"小倉 友昭", "name_2"=>"渋谷 和敏", "name_3"=>"かわぐち かお"},
    "_formatted"=>{"id"=>"1", "title"=>"神奈川県下北郡大間町仁井田潟中町", "director"=>"浜田 憲一", "director_kana"=>"はまだ けんいち", "json_field"=>{"hoge_id"=>"<em>hogehoge</em>", "foo_id"=>"7514", "name_1"=>"小倉 友昭", "name_2"=>"渋谷 和敏", "name_3"=>"かわぐち かお"}}},
   {"id"=>2,
    "title"=>"大阪府加茂郡東白川村曲新町",
    "director"=>"三宅 亜紀子",
    "director_kana"=>"みやけ あきこ",
    "json_field"=>{"hoge_id"=>"hogehoge", "foo_id"=>4865, "name_1"=>"河原 昌純", "name_2"=>"荒井 恩", "name_3"=>"きくち まさの"},
    "_formatted"=>{"id"=>"2", "title"=>"大阪府加茂郡東白川村曲新町", "director"=>"三宅 亜紀子", "director_kana"=>"みやけ あきこ", "json_field"=>{"hoge_id"=>"<em>hogehoge</em>", "foo_id"=>"4865", "name_1"=>"河原 昌純", "name_2"=>"荒井 恩", "name_3"=>"きくち まさの"}}}],
 "nbHits"=>500000,
 "exhaustiveNbHits"=>false,
 "query"=>"hogehoge",
 "limit"=>3,
 "offset"=>0,
 "processingTimeMs"=>20}

_formatted の値を見ると、

"json_field"=>{"hoge_id"=>"<em>hogehoge</em>"

になっているので、Valueにマッチしていますね。

三宅 で検索してみる

----------------------------------------------------------------------------------------------------
QUERY: 三宅
{"hits"=>
  [{"id"=>51674,
    "title"=>"京都府三宅島三宅村大野原町福田原",
    "director"=>"松本 星良",
    "director_kana"=>"まつもと せら",
    "json_field"=>{"hoge_id"=>"hogehoge", "foo_id"=>5441, "name_1"=>"石黒 雅民", "name_2"=>"矢野 沙於", "name_3"=>"にわ しゅうじ"},
    "_formatted"=>{"id"=>"51674", "title"=>"京都府<em>三宅</em>島<em>三宅</em>村大野原町福田原", "director"=>"松本 星良", "director_kana"=>"まつもと せら", "json_field"=>{"hoge_id"=>"hogehoge", "foo_id"=>"5441", "name_1"=>"石黒 雅民", "name_2"=>"矢野 沙於", "name_3"=>"に わ しゅうじ"}}},
   {"id"=>64707,
    "title"=>"東京都三宅島三宅村犬迫町",
    "director"=>"大竹 正博",
    "director_kana"=>"おおたけ まさひろ",
    "json_field"=>{"hoge_id"=>"hogehoge", "foo_id"=>8806, "name_1"=>"新谷 颯", "name_2"=>"金子 琢磨", "name_3"=>"しらい たまき"},
    "_formatted"=>{"id"=>"64707", "title"=>"東京都<em>三宅</em>島<em>三宅</em>村犬迫町", "director"=>"大竹 正博", "director_kana"=>"おおたけ まさひろ", "json_field"=>{"hoge_id"=>"hogehoge", "foo_id"=>"8806", "name_1"=>"新谷 颯", "name_2"=>"金子 琢磨", "name_3"=>"しらい たまき"}}},
   {"id"=>76362,
    "title"=>"北海道三宅島三宅村曽根",
    "director"=>"角田 孝志",
    "director_kana"=>"かくた たかし",
    "json_field"=>{"hoge_id"=>"hogehoge", "foo_id"=>7961, "name_1"=>"沢田 里澄", "name_2"=>"片岡 太誠", "name_3"=>"すだ ちお"},
    "_formatted"=>{"id"=>"76362", "title"=>"北海道<em>三宅</em>島<em>三宅</em>村曽根", "director"=>"角田 孝志", "director_kana"=>"かくた たかし", "json_field"=>{"hoge_id"=>"hogehoge", "foo_id"=>"7961", "name_1"=>"沢田 里澄", "name_2"=>"片岡 太誠", "name_3"=>"すだ ちお"}}}],
 "nbHits"=>3624,
 "exhaustiveNbHits"=>false,
 "query"=>"三宅",
 "limit"=>3,
 "offset"=>0,
 "processingTimeMs"=>1}

json_field よりも title などが優先されていそうな感じでしょうか?
(ネストが深いデータよりも浅いデータが優先されるのかもしれない?)

組み合わせで検索してみる

"しらい 山下"

----------------------------------------------------------------------------------------------------
QUERY: しらい 山下
{"hits"=>
  [{"id"=>466075,
    "title"=>"静岡県横浜市南区碇ケ関古懸鳥井",
    "director"=>"白井 朔実",
    "director_kana"=>"しらい さくみ",
    "json_field"=>{"hoge_id"=>"hogehoge", "foo_id"=>8146, "name_1"=>"山下 智規", "name_2"=>"奥山 麻友美", "name_3"=>"すどう にじと"},
    "_formatted"=>{"id"=>"466075", "title"=>"静岡県横浜市南区碇ケ関古懸鳥井", "director"=>"白井 朔実", "director_kana"=>"<em>し</em><em>らい</em> さくみ", "json_field"=>{"hoge_id"=>"hogehoge", "foo_id"=>"8146", "name_1"=>"<em>山下</em> 智規", "name_2"=>"奥山 麻友美", "name_3"=>"すどう にじと"}}},
   {"id"=>2895,
    "title"=>"茨城県西磐井郡平泉町下津林番条町",
    "director"=>"白井 一将",
    "director_kana"=>"しらい かずまさ",
    "json_field"=>{"hoge_id"=>"hogehoge", "foo_id"=>9577, "name_1"=>"藤岡 智博", "name_2"=>"山下 杏音", "name_3"=>"なかがわ つとむ"},
    "_formatted"=>{"id"=>"2895", "title"=>"茨城県西磐井郡平泉町下津林番条町", "director"=>"白井 一将", "director_kana"=>"<em>し</em><em>らい</em> かずまさ", "json_field"=>{"hoge_id"=>"hogehoge", "foo_id"=>"9577", "name_1"=>"藤岡 智博", "name_2"=>"<em>山下</em> 杏音", "name_3"=>"なかがわ つとむ"}}},
   {"id"=>68937,
    "title"=>"栃木県岡崎市上野新",
    "director"=>"白井 俊輔",
    "director_kana"=>"しらい しゅんすけ",
    "json_field"=>{"hoge_id"=>"hogehoge", "foo_id"=>3373, "name_1"=>"黒田 笑弥", "name_2"=>"山下 結衣", "name_3"=>"かわはら あきこ"},
    "_formatted"=>{"id"=>"68937", "title"=>"栃木県岡崎市上野新", "director"=>"白井 俊輔", "director_kana"=>"<em>し</em><em>らい</em> しゅんすけ", "json_field"=>{"hoge_id"=>"hogehoge", "foo_id"=>"3373", "name_1"=>"黒田 笑弥", "name_2"=>"<em>山下</em> 結衣", "name_3"=>"かわはら あきこ"}}}],
 "nbHits"=>18,
 "exhaustiveNbHits"=>false,
 "query"=>"しらい 山下",
 "limit"=>3,
 "offset"=>0,
 "processingTimeMs"=>4}

director_kanaしらい が入っていて
json_field.name_x山下 が入っている

filterでjson内の特定のデータを指定してみる

filterableAtrtibutues を更新して、ネストされたフィールドをfilterできるようにします。

require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'
  gem "meilisearch"
end

require "meilisearch"

MEILI_URL = "http://localhost:7700"

@index = MeiliSearch::Client.new(MEILI_URL, "api-key")
  .index("movies")

@index.update_filterable_attributes([
  'json_field.name_1',
  'json_field.name_2',
  'json_field.name_3',
])

def search(query)
  puts "-" * 100
  puts "QUERY: #{query}"
  pp @index.search(
    query,
    {
      attributesToHighlight: ['*'],
      limit: 3,
      filter: "json_field.name_1 = \"黒田 笑弥\"",
    },
  )
end

search("")

検索してみます。

----------------------------------------------------------------------------------------------------
QUERY:
{"hits"=>
  [{"id"=>68937,
    "title"=>"栃木県岡崎市上野新",
    "director"=>"白井 俊輔",
    "director_kana"=>"しらい しゅんすけ",
    "json_field"=>{"hoge_id"=>"hogehoge", "foo_id"=>3373, "name_1"=>"黒田 笑弥", "name_2"=>"山下 結衣", "name_3"=>"かわはら あきこ"},
    "_formatted"=>{"id"=>"68937", "title"=>"栃木県岡崎市上野新", "director"=>"白井 俊輔", "director_kana"=>"しらい しゅんすけ", "json_field"=>{"hoge_id"=>"hogehoge", "foo_id"=>"3373", "name_1"=>"黒田 笑弥", "name_2"=>"山下 結衣", "name_3"=>"かわはら あきこ"}}}],
 "nbHits"=>1,
 "exhaustiveNbHits"=>false,
 "query"=>"",
 "limit"=>3,
 "offset"=>0,
 "processingTimeMs"=>0}

json_field.name_1 が一致するデータが返ってきますね。

まとめ

  • 日本語対応で形態素解析されるようになった
  • v0.26で入ったAutoBatchingは便利
    • ※experimentalなので要注意
  • ネストされたjsonデータも検索可能
    • filterもネスト可能

Discussion