はじめに
classiでは全文検索でElasticsearchを使用しています。今年を振り返って改めてclassiでの使われ方を紹介したいと思います。
ちなみに実装言語としてruby、フレームワークとしてRailsを使っています。mappingの定義やindexの定義の仕方はelasticsearch-rails(elasticsearch-model)での書き方で書いてます。ご了承ください。
どのような使い方をしているか
classiでは主に以下の機能でElasticsearchを使っています。
- テスト、問題、アンケート、自分であげた画像に対するキーワード検索
- 先生・生徒のコミニケーション機能の各メッセージに対してのキーワード検索
- 動画コンテンツのキーワード検索
では順にどのような使い方をしているかを説明します。
テスト、問題、アンケート、自分であげた画像に対するキーワード検索
ここでは検索対象のデータをjson形式にしてElasticsearchに登録しています(普通の使い方ですね)。versionもまだ2系( )なので、mappingも以下のような形(例)で定義しています。
indexes :id, type: 'long', index: 'not_analyzed'
indexes :name, type: 'string', analyzer: 'kuromoji_analyzer', fields: { raw: { type: 'string', index: :not_analyzed } }
indexes :owner_id, type: 'long'
indexes :sentence, type: 'string', analyzer: 'kuromoji_analyzer'
versionが5系であれば、type: 'string'
でなくtype: 'text'
になりますが、まだversion2系のままなので、string
になっています。
また検索クエリーではキーワード検索のところでsimple_query_string
を使っています。
simple_query_string:
{ query: "\"#{@condition_params[:keyword]}\"",
fields: ['name', 'sentence'],
default_operator: 'and',
}
ここにあるようにキーワード検索クエリにはいくつか種類がありますが、ファイル名にアンダーバーがある場合が結構あったため、simple_query_string
を使うことにしました。
上でも書いている通りversionが2系なので、近々バージョアップをしていく予定です。その場合は、mappingの定義string
と書いているところをtext
に変更するなど多少手直しが必要になりますが、バージョンを古いままにしておくわけにはいかないので、対応していくつもりです。
先生・生徒のコミニケーション機能の各メッセージに対してのキーワード検索
ここでも検索対象となる投稿本文のデータをjson形式にしてElasticsearchに入れています。データの形式はメッセージとそれに対するコメントが1対多になっています。検索時にはそのメッセージとコメントの中をみて検索キーワードに該当するものを抽出します。そのため今回はメッセージとコメントを一つのjsonに入れてElasticsearchに登録しています。
mappingの書き方としては、以下のようにします。
indexes :id, type: 'long'
indexes :body, type: 'text', analyzer: 'kuromoji_analyzer'
indexes :comments, type: 'nested' do
indexes :id, type: 'long'
indexes :body, type: 'text', analyzer: 'kuromoji_analyzer'
end
nestedを使うことで1対多のデータを一つのjsonとしてElasticsearchに入れることができます。
検索時にはmessageのbodyとcommentsのbodyをそれぞれみて検索するようにします。こういう形式のデータでも手軽に検索できるのはElasticsearchのような検索エンジンの利点だと思います。
バージョンアップ
この機能で使っているのはversionが5系です。最新は6系なのでバージョンアップをしなければなりません。Amaozon Elasticsearch Serviceでは簡単にアップデートできる仕組みを提供しています。
ここの青い枠で囲っている「ドメインのアップグレード」からElasticsearchのバージョンアップができます。自分が試して見たところノーメンテで出来ました。
動画コンテンツのキーワード検索
こちらは私が直接担当しているものではないのですが、以前mapping定義やqueryを見たところ検索時に各要素にscore(キーワードに対するマッチ度)を付けて検索結果の並び順を導き出しています。scoreの出し方はqueryを以下のように書いてやっています。例ですが、functionsの中に独自でscoreの計算方法を独自で設定する場合は定義していきます。
query: {
function_score: {
score_mode: 'sum', # functionsないのスコアの計算方法
boost_mode: 'multiply', # クエリの合計スコアとfunctionのスコアの計算方法
query: {
bool: {
must: {~~~~~~},
}
},
functions: [
{
field_value_factor: {
field: "field1",
factor: 2,
modifier: "square",
missing: 1
},
weight: 5
},
{
field_value_factor: {
field: "field2",
factor: 3,
modifier: "sqrt", # squt: ルート
missing: 1
},
weight: 2
}
]
}
},
これだとfield1
の値を2乗してfactor
の値をかけます。そしてその値にweightとして5をかけます。
もう一つのfield2
の値のルート値にfactor
の値をかけます。そしてweightとして2をかけます。
以上の値を足し合わせ、さらにquery実行時に出たscoreの値を全てsum
(足し合わせる)することで検索結果で算出されるscoreが出ます。
以上です。
今後やりたいこと
来年やりたいこととして、まずは古いElasticsearchのバージョンを上げようと思っています。6系に揃えたいと思います。
個人的にはpluginを作って機能拡張をしてみたいという気持ちがあります。間に合えば今回の記事にそれを含めたいと思っていました。が、すみません、間に合いませんでした。
その件は後日また。