stop-arret

Elasticsearch多言語化その1

英語でもそこそこの検索結果が出て欲しい

以前、Elasticsearch の analyzer 関連の投稿を書いた。

Elasticsearch の analyzer 関連の設定で知ってることを全て書く

Elasticsearch を何に使っているかなどは、詳しくはそちらを参照してもらうとして、ポイントだけ抜粋しておく。

  • GitHub, Slack, Google Drive, ChatWork, Backlog などからAPI経由でデータを取ってきて、インデックスを作成
  • 言語は、日本語がメインだけど、海外の人とのやりとりや、英語のwebページ(StackOverflowとか)からのコピペもあるので、英語もある程度使われている。

現状は、日本語にのみ対応した設定だけど、英語もそこそこ使われているので、英語の検索結果もそれなりの精度になって欲しい、というのが今回の話。

やったこと: 英語の stemmer を filter として追加

先に結論を書いておくと、使用している analyzer に、”english” と “possessive_english” という2つの stemmer を filter のところに追加した。

設定方法などは、詳しくは以下のページを参照。

Stemmer Token Filter | Elasticsearch Reference [5.0] | Elastic

多言語化のいくつかのポイント

結論を先に書いたところで、Elasticsearch で多言語を扱うときのポイントなどを、公式ドキュメントを元に書いてみる。

以下の公式ドキュメントを全て読んだ人は、本ブログ投稿は無用だと思う。

Dealing with Human Language | Elasticsearch: The Definitive Guide [2.x] | Elastic

あと、Elasticsearch の基本的な知識があることを前提としている。

敵を知り己を知れば云々

まずは、敵(検索対象のドキュメント、ユーザーのユースケース)を知って分類・整理すると良さそう。

ドキュメントに関しては、以下のような観点で分類できそう。

  • どの単位で言語が異なるか
    • ドキュメント毎(1ドキュメント=1言語)
    • フィールド毎(1フィールド=1言語)
    • 1フィールドに複数言語が混在(今回はこれ)
  •  メインの言語、サブの言語で分けられるか
    • 分けられる(今回はこちら。日本語メインで、英語がサブ)
    • 分けられない
      • 同じ内容のドキュメントが複数言語で存在する(Wikipedia とか)
      • 各国毎にローカライズされている企業のホームページ(各国支社によって、ページの内容が異なる)

ユーザーに関しては、こんな感じ?

  • メイン言語あり、なし
    • あり
      • 例えば、ある事柄のWikipediaページが複数言語であれば、日本語版を優先して出したい
      • (その他、ドキュメントにメイン、サブの言語がある場合は、必然的に「あり」になる)
    • なし(使用者は、複数言語の文章を読むことが可能)
  • 言語設定を取得可能
    • システムの設定で、使用言語が設定できる(Google, Facebook などのように)
    • そのような設定はない
      • ブラウザの accept-language で判定
      • IP アドレスなどで判定

ドキュメント毎 vs フィールド毎

「どの単位で言語が異なるか」は、公式ドキュメントの分類をそのまま援用したが、「ドキュメント毎」と「フィールド毎」は、特殊な例を除くと本質的には一緒な気がする。title と body という2つの情報があった場合、title だけが複数言語で body が1言語のみ、という事はあまりないはず。

従って、複数言語のデータがある title, body を、

  • 1つのドキュメントの複数フィールド(title_en, title_ja, body_en, body_ja, etc.)に格納する
  • 複数インデックス(index_en, index_ja, etc.)の同一フィールド(title, body)に格納する

のどちらの方法で格納するか、という実装上の選択になると思う。

どちらが良いかだが、長所短所をまとめてみた。

  • 単一インデックス複数フィールド
    • (公式ドキュメントには記載がないが)複数インデックスに比べると、単一インデックスの方が管理が楽だと思う。snapshot & restore, reindex など。
    • フィールドの追加は後からでも出来るが、フィールドに analyzer を指定するのは、インデックス作成時にしか出来ないので、何らかの workaround が必要
  • 複数インデックス同一フィールド
    • 言語の追加は、インデックスを作成するだけなので楽

ちなみに、複数言語を複数「タイプ」に入れてはいけない。詳しくは、以下のページのDon’t Use Types for Languages の項を参照。

One Language per Document | Elasticsearch: The Definitive Guide [2.x] | Elastic

1つの文章に複数言語が混じる場合

1つの文章に複数言語が混じるパターンは、大きく分けて2つあると思う。

  • 外国語の単語が混じる
  • サブ言語の文章が混じる

前者だと、日本語文章に英語の単語(hello, index, database)が混じったり、英語にフランス語由来の単語(deja vu, faux pas など)が混じったりとか。後者の例としては、日本語の文章に英語のマニュアルからの引用を入れたりとか。今回の自分達のユースケースは後者。

外国語の単語が混じる場合は、analyzer としてはメイン言語に合わせて設定して、外国語の単語を辞書として登録していくのが良さそう。(試してはいない)

複数言語の文章が混じるパターンでは、複数のフィールドなりドキュメントに分けて(前項を参照)、別々の analyzer でインデックスするというのが基本になると思う。

「複数の言語」のパターン

ただ、複数言語でも、英語・フランス語のパターンと、日本語・英語のパターンでは事情が異なる。

例えば、英語とフランス語の場合、使うアルファベットは一緒で、フランス語の場合はアクセント記号 (accent aigu, accent grave, etc.)が混じる。従って、例えば英語向けの stemmer をフランス語のフィールドに適用しても良い結果は得られないし、かと言って同じフィールドに対して英語とフランス語の stemmer を適用しても、これまた良い結果にはならない。詳しくは以下のページを参照。

Pitfalls of Mixing Languages | Elasticsearch: The Definitive Guide [2.x] | Elastic

つまり、同じような文字を使う複数の言語を扱う場合は、前項の通り異なるフィールドなり異なるインデックスに別々に配置する必要がある。

それに対して、日本語と英語の場合、使う文字が全く異なる。上のページの Stemmer per Script のところでイスラエルではヘブライ語、アラビア語、ロシア語(キリル文字)、英語という異なる文字を使っている例が出ているが、これと同じことが日本語と英語にも言える。

ということで、日本語メインで英語が混じるテキストの場合、1つのドキュメント・フィールドに格納して、日本語向けの設定と英語向けの stemmer を両方適用しても問題は起きない。(これは、「異なる言語は異なるフィールドあるいはインデックスに格納する」という原則から外れる例外と言っても良いかもしれない。)

まとめ

一言で Elasticsearch を多言語対応すると言っても、色んなパターンがあることが分かった。ユースケースを整理して、最適な実装上の選択をする必要がある。

今回の自分達のケースでは

  • 使われるのは日本語がメイン、英語がサブ
  • 1つの文章で日本語と英語が混じる

だったので、1つのフィールドで、日本語向けの設定に英語の stemmer を組み合わせて使った。

今後

本投稿のタイトルに「その1」と含めてあるが、その2以降も各予定。

今後は、他国のチームでも使うことを想定して、システムを拡張していきたい。

  • メイン言語+英語というのは変わらない
  • 「メイン言語」の特徴は色々ありそう
    • 非アルファベットの言語(タイ語、中国語、ロシア語)
    • アルファベットメインの言語(フィリピン語、ベトナム語も?)

その場合、メイン言語とサブ言語でフィールドを分ける必要がありそう。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です