Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
mimiのElasticsearch活用例/mimi-es
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
yazaki_r
September 19, 2017
Programming
3k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
mimiのElasticsearch活用例/mimi-es
yazaki_r
September 19, 2017
Other Decks in Programming
See All in Programming
The NotImplementedError Problem in Ruby
koic
1
860
DynamoDBには集計系のクエリがないけどなんとかしたい
musan
1
180
正しくソフトウェアを作る、前提を疑うための認知の視点 / doubt-premise
minodriven
21
6.8k
Javaの型とAI時代に型が大事な理由 / java types and type in AI era
kishida
2
140
TSKaigi Night Talks 2026_TypeScriptでサプライチェーンの整合性を型に閉じ込める
geekplus_tech
0
400
軽量Java基盤の設計 DIコンテナに頼らない、長期保守と1秒起動の実現 JJUG CCC 2026 Spring
macha64
0
550
AIを活用したE2Eテスト実装効率化のあゆみ / ebisu-mobile-14-kotetu
kotetuco
0
110
C# and C++ Interoperability - cho-dotnetnew
harukasao
0
290
PHPで使える日時の表現と、その知り方 #frontend_phpcon_do
o0h
PRO
0
260
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
3
720
AI時代のUIはどこへ行く?その2!
yusukebe
22
7.4k
Agentic UI
manfredsteyer
PRO
0
180
Featured
See All Featured
Designing Experiences People Love
moore
143
24k
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
600
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
560
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.8k
Ten Tips & Tricks for a 🌱 transition
stuffmc
0
140
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.1k
HTML-Aware ERB: The Path to Reactive Rendering @ RubyCon 2026, Rimini, Italy
marcoroth
1
210
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.3k
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
The Invisible Side of Design
smashingmag
301
52k
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
240
Highjacked: Video Game Concept Design
rkendrick25
PRO
1
400
Transcript
mimiのElasticsearch活用事例 2017.09.11 yazaki_r@mimiLab
自己紹介 氏名:矢崎亮太 所属:株式会社mimiLab 役割:PM 兼 サーバサイドエンジニア
今日話すこと ・mimiの紹介・検索機能 ・Why Elasticsearch? ・インデックス再構築事例 ・今後やりたいこと ・検索事例
mimi とは? 好きなタイプ(顔)で検索できるマッチングアプリ 24時間/365日の監視体制 身分証明書による年齢確認 独自の顔認証システム 2016年12月リリース 好きなタイプ(顔)で検索できる! 【特徴】
機能紹介:タイプ検索(1) 好きなタイプ(顔)で検索できる! 【プリセットされたタイプ例】 ・キレイ系/可愛い系女子 ・ショートカット女子 ・メガネ女子 ・高身長/低身長女子 ・スレンダー/グラマー女子 ・金髪/黒髪女子 などなど。
※女性で登録すれば男性も検索可能です。
機能紹介:タイプ検索(2) 【設定可能条件】 ・年齢 ・居住地 ・加工画像排除 ・目/鼻/口/眉など ・髪型/髪色/体型/肌の色など ・メガネ/八重歯/鎖骨など カスタムタイプで検索条件を細かくできる! 【設定例】
・年齢:18 - 22歳 ・居住地:東京 AND 神奈川 ・加工画像排除ON ・目:奥二重 ・髪型:ロング ・髪色:黒髪 ・その他:八重歯 他にもマニアックな設定が色々できるよ!
機能紹介:タイプ検索(3) 男女で検索項目が違う! 男性の検索画面 【男性の設定項目】 ・塩顔/しょうゆ顔/ソース顔 ・ウマ顔/ネコ顔/サル顔/ヘビ顔 ・ヒゲ有/無 など 【女性の設定項目】 ・キレイ系/カワイイ系 ・黒髪/金髪
・泣きボクロ/えくぼ/うなじ など 女性の検索画面
機能紹介:リスト検索 一覧からも検索できる! 【設定可能条件】 ・年齢 ・居住地 ・加工画像排除 ・年収/職業/血液型など ・趣味・よく行く場所など ・タバコ/お酒の頻度など ・結婚の意思/デート費用など
・登録日/最終ログイン日など
特徴:豊富な検索機能 カスタム検索 【設定可能条件】 ・年齢 ・居住地 ・加工画像排除 ・目/鼻/口/眉など ・髪型/髪色/体型/肌の色など ・メガネ/八重歯/鎖骨など }
} 完全一致 スコアマッチ ※一致している人だけ出したい ※一致している順で出したい 基本条件 見た目条件
それゆえ要件が多い 【機能要件一部】 ・男女で検索項目が異なるのでそれぞれ検索したい ・一部項目は完全一致で検索したい(居住地など) ・さらに年齢などは範囲検索したい ・見た目条件など条件一致率が高いものから順に表示したい ・「いいね」か「イマイチ」した相手は表示しない などなど ※他にもユーザーの属性 /状態によって優先表示する内容や並び順を変えたりしています。
Why Elasticsearch? ・検索機能が豊富! - 見た目条件など条件一致率の高い順に表示したい場合、Elasticsearchの _scoreフィールドが役立ちそう。 ・高パフォーマンス! - 表示するアルゴリズム上、幾つかの条件を検索/計算する必要があるた め、MySQLなどではレスポンスタイムを担保できない。
- クエリを何度も投げずに目的の検索機能を実現できそう。
構成 EC2 ELB Aurora(Master) Aurora(Slave) ×n台 ×n台 検索機能要件を満たすために検索に関わるデータのみElasticsearchに格納している VPC Internet
Gateway Redis Elasticsearch
検索事例
検索事例 ・基本的にスコア付けはboolクエリを応用{ "mimi_matching": { "mappings": { "appearance_female": { "properties": {
"academic_career": { "type": "long" }, Must クエリ{ And条件。 filterと違いスコアが計算される。 Should クエリ Or条件。 filterと違いスコアが計算される。 Filter クエリ And条件。 スコアが計算されない。
検索事例 【要件】 ・男女で検索項目が異なるのでそれぞれ検索したい curl -XGET 'http://******/mimi_index/_mapping?pretty' { "mimi_index": { "mappings":
{ "appearance_female": { "properties": { "academic_career": { "type": "long" }, …… curl -XGET 'http://******/mimi_index/_mapping?pretty' { "mimi_index": { "mappings": { "appearance_male": { "properties": { "academic_career": { "type": "long" }, …… →男女でtypeを分ける 男性用 女性用
検索事例 【要件】 ・一部項目は完全一致で検索したい(居住地など)/ 年齢などは範囲検索したい(1) "mimi_index": { "mappings": { "appearance_male": {
"properties": { "living_place": { "type": "long" }, "age": { "type": "long" }, //// 以下略 →居住地は居住地ID(long)を、年齢も数値(long)を保存。 マッピング 居住地(living_place):東京(ID:1) 年齢(age):20歳 “fields”:{ "living_place": 1, "age": 20, } ※居住地IDは仮 保存内容例 保存内容例
検索事例 【要件】 ・一部項目は完全一致で検索したい(居住地など)/ 年齢などは範囲検索したい(2) →bool クエリでmust/range検索 "query": { "bool":{"must":[ {"range":
{"age":{"gte":18,"lte":22}} }, {"terms": {"living_place":[1,2]} }]} } クエリ例 居住地(living_place):東京or神奈川 年齢(age):18歳以上22歳以下 クエリ例 WHERE (`age` >= 18 AND `age` <= 22 ) AND `living_place` IN (1,2); MySQLだとこんな感じ
検索事例 【要件】 ・さらに見た目条件は一致率が高いものから順に表示したい(2) "mimi_index": { "mappings": { "appearance_male": { "properties":
{ "eye": { "type": "long" }, "hair_color": { "type": "long" }, //// 以下略 →見た目マスタID(long)を保存。 マッピング 目(eye):ぱっちり二重(ID:1) 髪の色(hair_color):黒髪(ID:1) “fields”:{ "eye": 1, "hair_color": 1, } ※見た目の各IDは仮 保存内容例 保存内容例
検索事例 【要件】 ・さらに見た目条件は一致率が高いものから順に表示したい(2) →bool クエリでshouldでterms検索、_scoreでソート "query": { "bool":{"should":[ {"terms": {"eye":[1,2]}},
{"terms": {"hair_color":[1,2]}} ] }, "sort":[ {"_score":"desc"} ] クエリ 目(eye):ぱっちり二重 , 奥二重 髪の色(hair_color):黒髪 , 茶髪 クエリ例 実現できない! MySqlだと、、、
検索事例 【要件】 ・「いいね」か「イマイチ」した相手は表示しない →bool クエリでmust_notで非表示対象を指定 "query": { "bool":{"must_not":[ {"terms": {"_id":["*******","**********"]
}} ]}} クエリ 非表示対象はRedis など別領域に保存
インデックス再構築事例
インデックス定義やシャーディングの設定は、 作成時に決められるため、 すでに決められたタイプなどの再定義はできない。 そのため、切り替え方法を工夫する必要がある。 インデックス再構築事例
インデックス再構築事例 リスト画面が重い → Elasticsearchで検索したい 【設定可能条件】 ・年齢 ・居住地 ・加工画像排除 ・年収/職業/血液型など ・趣味・よく行く場所など ・タバコ/お酒の頻度など ・結婚の意思/デート費用など
・登録日/最終ログイン日など 元々ここはMySQLで検索する想定だっ たため、Elasticsearchの検索フィールド には何も入っていなかった。
インデックス再構築事例 - 問題点 【設定可能条件】 ・年収/職業/血液型など ・趣味・よく行く場所など ・タバコ/お酒の頻度など ・結婚の意思/デート費用など ElasticSearch には格納されていない
フィールド多数ある 【設定可能条件】 ・登録日/最終ログイン日 たまたま登録されていたが、 フィールドのtype が 想定と違う "created": { "type": "string" }, インデックス再定義が必要
インデックス再構築事例 - やること (1)別インデックス再構築 (2)再構築したインデックスへの切り替え (案1)ES側でエイリアスを作成して切り替える (案2)アプリケーション側で調整して切り替える インデックス定義やシャーディングの設定は、作成時に決められるため、 すでに決められたタイプなどの再定義はできない。 そのため、切り替え方法を工夫する必要がある。
インデックス再構築事例 - インデックス再定義実行 ・別インデックスを作成 / 足りないフィールドを追加したマッピングを作成{ "mimi_matching": { "mappings": {
"appearance_female": { "properties": { "academic_career": { "type": "long" }, "mimi_index_v2": { "mappings": { "appearance_male": { "properties": { "blood_type": { "type": "long" }, "create_time": { "type": "date", "format": "yyyy-mm-dd HH:mm:ss" }, "last_login_time": { "type": "date", "format": "yyyy-mm-dd HH:mm:ss" }, マッピング 登録時間(create_time):2017-08-30 11:00:00 ログイン時間(last_login_time):2017-08-30 11:00:00 保存内容例
インデックス再構築事例 -(案1)エイリアスを作成して切り替える Application ・現状 mimi_index mimi_index_new インデックス 旧インデックス 新インデックス
Application エイリアス ・エイリアスを作成する mimi_index mimi_index mimi_index_new インデックス 旧インデックス 新インデックス インデックス再構築事例
-(案1)エイリアスを作成して切り替える
Application エイリアス ・re_index API でドキュメントをコピー mimi_index mimi_index mimi_index_new インデックス re_index
旧インデックス 新インデックス インデックス再構築事例 -(案1)エイリアスを作成して切り替える
Application エイリアス ・ mimi_index mimi_index mimi_index_new インデックス 旧インデックス 新インデックス ・
エイリアスの付け先を変更する インデックス再構築事例 -(案1)エイリアスを作成して切り替える
インデックス再構築事例 -(案1)エイリアスを作成して切り替える ・元々同期していないMySQL上のデータは? ・サービス稼働中にドキュメントコピーできるの? ・切り替え後、切り戻しはどうやる? (古いインデックスには古いデータしかない) 疑問点
インデックス再構築事例 - (案2)アプリケーション側で調整する Application ・現状 mimi_index mimi_index_new インデックス 旧インデックス 新インデックス
インデックス再構築事例 - (案2)アプリケーション側で調整する Application ・ mimi_index mimi_index_new インデックス 旧インデックス 新インデックス
INSERT/SELECT INSERT only ・更新/参照は旧インデックス、新インデックスにも更新を行うようにする
Application 同期ツール SELECT データ同期 ・同期ツールを作成して新インデックスへデータ同期{ ※MySQLテーブルを正にして新インデックスへ同期するツールを作った ※ESはあくまで検索のためだけに使う想定なので、同期元(マスタ)はMySQLテーブルのデータにしている mimi_index_new インデックス再構築事例 -
(案2)アプリケーション側で調整する INSERT only mimi_index_old INSERT/SELECT INSERT/SELECT
Application mimi_index mimi_index_new インデックス 旧インデックス 新インデックス INSERT/SELECT INSERT only ・アプリケーションで接続先切り替え
更新/参照は新インデックス、旧インデックスにも更新を行うようにする インデックス再構築事例 - (案2)アプリケーション側で調整する
インデックス再構築事例 - (案2)アプリケーション側で調整する ・元々同期していないMySQL上のデータは? →同期ツールで解決 ・サービス稼働中にドキュメントコピーできるの? →同期ツールで解決 (MySQLテーブルを正にして、アプリケーションとバッチの双方から書き込み) ・切り替え後、切り戻しはどうやる? (古いインデックスには古いデータしかない)
→古いインデックスにも書き込みを続けているので切り戻しOK 疑問点
インデックス再構築事例 - 結果 案2で対応。 エイリアスもre_indexAPIも使わずに インデックスの再構築(サービス無停止)を行いました。
今後やりたいこと(1) ・特定条件によってFunctionScore クエリで重み付けしたい "mappings": { "appearance_female": { "properties": { "academic_career":
{ "type": "long" }, "query": { "function_score": { "query": { "bool": { "should": [{ "term": {"eye":[1,2],}}]} }, "score_mode": "sum", "boost_mode": "multiply", "functions": [{{ "filter": { "term": { {"age":{"gte":25,"lte":29}}}}, "weight": 10 }, {"filter": { "term": { {"age":{"gte":20,"lte":24}} }}, "weight": 5 }, クエリ ユーザーによって年齢の近い順など 様々な条件で重み付け これにより様々な条件で ユーザーを並べ替えられる! マッチングサービスな のでコレ大事
今後やりたいこと(2) Parent-Childを使用して 非表示対象ユーザーを除外したい 【親ドキュメント】 【子ドキュメント】 除外対象
None
ご清聴ありがとうございました。 以上。