読者です 読者をやめる 読者になる 読者になる

よしだのブログ

サブタイトルはありません。

SolrCloud のリカバリー処理

IT、プログラミング Solr 検索エンジン

こんにちは!ご無沙汰しております。 この記事は Solr Advent Calendar 2016 の 1日目です!

qiita.com

一日目の出だしにしてはかなり渋め(アドバンスド)な内容かなと思いますが、SolrCloud のリカバリー処理についてコードを読んだり調べてみたので書いてみたいと思います。しかし、特に更新が非常に多い Solr を運用している場合は、最後だけでも是非読んで下さい。読まないと、全台ダウンしちゃいますよ!

今回は、特に文章だらけで申し訳ありませんが、よろしくお願いいたします。

前提

  • SolrCloud をざっと触ったことがあり、複数のレプリカやシャードの構成を組んだり使ったことがあることがある読者を前提に書きます。
  • Solr 5.5 のリカバリー処理について書きます。Solr 6 もそんなに違わないと思いますが。

リカバリー処理とは?

リカバリー処理とは、SolrCloud環境で同一シャード内のレプリカでインデックスデータの同期が失われた場合に、再度同期をとるために Solr によって行われる処理です。 例えば、1シャード3レプリカの3台の構成で、そのうちの1台がダウンしていた場合にインデックスの更新が行われた後、ダウンしていたサーバーが復旧すると、リカバリー処理が行われダウン中に実施されたインデックスの更新が反映されます。 ダウンしていたサーバーが復旧すると Solr Admin の画面で、Recovering となっているとこの処理が行われています。

その前にトランザクションログについて

SolrCloud の構成では、各 Solr のインスタンスごとにトランザクションログ(もしくはアップデートログ、移行 tlog と記載します) を保持しています。この tlog は SolrCloud の Near Realtime Search とデータの確実性を保つために導入されたファイルです。tlog には、データベースのトランザクションログと同様に更新リクエストのインデックス処理前のそのままのデータが記載されています。

SolrCloud ではあるインスタンスに更新データが届くと以下のような処理が行われます。

  1. tlog に書き込む、この際確実にディスクに書き込まれたことを確認する (fsynch)
  2. 書き込まれたことを確認したら、インデックスをメモリ(Java のヒープ上)だけに反映する (soft commit)
  3. (commitされると) メモリ上のインデックスデータを、インデックスのファイルに書き込む (hard commit)

hard commit は、/update?commit=true を送ったりすると行われます。

この時、2 と 3 の hard commit を実行する前にインスタンスが落ちると、インスタンスのヒープ上にしか無い更新データは消えてしまいます。 消えてしまうと困るので、インスタンスが復旧した際に tlog の有無を確認し、あった場合 tlog を再度適用し(リプレイといいます)、インデックスに反映します。ちなみにこの時行われるリプレイでは、いきなりインデックスのファイルに書き込まれます。

これがトランザクションログの役割で、インスタンス1つだけに注目した場合の処理です。以下の記事がこの辺のことを詳細に書いてあるのでご参考に。

lucidworks.com

では、レプリカ1にはインデックスがあって、レプリカ2がディスク障害でインデックスが飛んでしまった場合はどうでしょうか?

リカバリー処理の流れ

インスタンスをまたがったインデックスの障害のケースでも対応できるようにリカバリー処理は作られています。

まず、リカバリーはインスタンスがコレクションに参加した時に必ず行われます。この参加時とは、新規に追加した場合以外にも、ダウンしていたインスタンスが起動した場合も含まれます。この時、リカバリー対象のノードとリーダーノードのデータを比較します。 比較した結果トランザクションログとインデックスに差異がなければ処理は何も行われません。差異があった場合に、実際のリカバリーの処理が行われます。ちなみに、インスタンスを停止してすぐに起動しても一瞬リカバリーに入るのはこのチェックをしているためです。

また、自分自身がリーダーノードである場合も実際の処理は行われません。後述しますが、リーダーノードを正しいデータとしてリカバリーが行われるためです。

対象のノードがフォロワーで、リーダーノードのデータと差異がある場合にのみ、インデックスに対する処理は行われます。実際のリカバリー処理は以下の3ステップで行われます。

1. tlog のリプレイ

まず、tlog がある場合はリプレイします。ここまでは、1台のケースと同じです。

2. PeerSync

次に PeerSync と呼ばれる処理が行われます。

PeerSync とはインスタンスのダウン中に、インデックスの更新リクエストがされ、ダウンしていない同一シャード中の他のサーバーでインデックスが更新された場合に同期するための処理です。ダウンしていたインスタンスでは、PeerSync はリカバリー処理時には必ず実行が可能かチェックされます。具体的な実行が可能かどうかはどのぐらいインデックスに差異があるかを確認し、差異が少なければ PeerSync を行います。

PeerSync はリーダーのノードが保持している tlog と、自分の tlog を比較し大量の差異が無い場合は、行われていない tlog のみをコピーしリプレイを行いインデックスの同期を行います。tlog をコピーするため、tlog の同期も行われます。PeerSync の同期に成功した後はこの後のレプリケーション処理は行いません。

PeerSync が実行可能かどうかのしきい値は、トランザクションログ1ファイルに最大何件保持するかという設定 numRecordsToKeep に依存しています。numRecordsToKeep の件数を 100% とし、自分の新しいドキュメントの新しい方から 20% のインデックスのバージョンが、リーダーの新しい方から 80% のインデックスバージョンよりも古い場合は PeerSync しません。また、逆に自分のインデックスが新しい場合ももちろん PeerSync しません。わかりやすく書くと、単純な更新処理の場合、tlog 1ファイルに保持する最大件数(numRecordsToKeep)が 100 の場合、ダウン中に更新されたドキュメントが 60件未満なら PeerSync 、それ以上ならレプリケーションが行われます。

なぜ、全て PeerSync でリカバリーが行われないかというと、tlog はインデックスの情報ではなく処理前の更新リクエストがそのまま保持されているので、データのサイズが大きくなりがちで、さらに、リプレイ時にインデックス処理が行われるため比較的時間がかかること、tlog には全データを保持していないことなどの理由があると思われます。

3. レプリケーション

PeerSync で同期できない程度にインデックスに差異があった場合に行われるインデックスの同期処理が、レプリケーションです。

レプリケーションではインデックスのバイナリファイルごとリーダーからコピーし、同期をとる処理です。バイナリファイルはインデックスのセグメントごとに分割されており、差異があるセグメントのインデックスファイルのみコピーしインデックスの同期をおこないます。

レプリケーションでは、セグメントごとにわかれたインデックスファイル単位でコピーするため、Optimize などセグメント全体に作り変えが発生する処理を、サーバーのダウン中に行うと全インデックスのコピーが起きるため、レプリケーションに非常に時間がかかるので注意が必要です。ちなみに、レプリケーションではトランザクションログの同期は行われないので、ある程度の件数が新規に更新され、tlog の同期が取れるようになるまでは、ダウンしていたインスタンスを単純に起動・停止するだけでこのレプリケーションまで処理が進み、ファイルはコピーされずに終了します。

また、リカバリー中の更新リクエストはトランザクションログの buffered update という箇所に別途保存され、レプリケーション後にリプレイされます。リプレイ中にも受け取った更新リクエストは buffered update に追記されリプレイされ、全てのリプレイ処理が完了したのちに status が active になります。

何がリカバリー処理のトリガーとなるか?

リカバリー処理のトリガーとなる現象は、インデックスデータに差異が見つかること以外にもいくつかあります。例えば、更新処理時にリーダーからフォロワーにデータが転送されるのですが、この転送が失敗したり、フォロワーでのインデックス処理が失敗したと判断されると、リーダーからフォロワーにリカバリーを行うよう、リクエストが送信されます。

numRecordsToKeep の値に注意!

このリカバリー処理、よく出来ているのですが、更新リクエストが非常に多いユースケースについては注意が必要です。どういうことかというと、気にせずにデフォルト設定で使用すると、リカバリーがいつまでたっても終わらない、ということが起こりえます。

デフォルトの設定ではトランザクションログ1ファイルあたりに保持できるレコードの件数を示す、numRecordsToKeep の設定が 100 しかありません。更新処理が大量にある場合にリカバリーに入ると、ダウン中に発生する更新処理がしきい値を簡単にオーバーするので PeerSync は行われず、レプリケーションに入ります。レプリケーションでは、比較的時間のかかるインデックスのコピー処理が開始されますが、その間にもどんどん更新リクエストが入ってきます。入ってきた更新処理は、リプレイされインデックスに順次反映されますが、コピー中にたまった更新リクエストの数が多いと、リプレイ中にもどんどんトランザクションログに更新リクエストが貯まるので、終わらないという状態になります。

このリカバリー中のインスタンスは検索はできるのですが、検索結果が古く正しくないので、一般的なシステムではリカバリー中のサーバーには検索リクエストを飛ばさないようにすることが多いです。1台がずーっとリカバリー中だと、その分、外のサーバーに検索リクエストの負荷がかかるので、放おって置くと次々にサーバーがダウンし、全台ダウンすることがあります。

なので、numRecordsToKeep の値を大きめに設定することで、できるだけリカバリー処理を PeerSync で済ませることがベスト・プラクティスとなります。ただし、numRecordsToKeep を大きくするとディスクを大量に食うので注意が必要です。

まとめ

numRecordsToKeep の値を大きくするのはもちろんですが、適切な値を決めるには徹底的な負荷検証とチューニングをお忘れなきよう。

明日のアドカレは近藤さん (tkondo) による、更新処理のパフォーマンスに関するないようになりそうですー!乞うご期待。

qiita.com

embulk-output-solr を公開しました!

IT、プログラミング 検索エンジン Solr

こんにちは! fluentd の兄弟で、オープンソースのバルクローダー Embulk の Solr 用 Output プラグイン embulk-output-solr を公開しました。 ぜひご利用ください。Github のリポジトリは以下です。

https://github.com/yahoojapan/embulk-output-solr

使い方

まず gem をインストールします。

embulk gem install embulk-output-solr

以下のような設定を embulk の config.yaml に記載します。以下の例では、localhost:8983 の Solr の mytest というコレクションに対してデータをフィードします。bulkSize は一度に送るドキュメント数で、idColumnName は id を示すフィールドの名前を記載します。

out:
  type: solr
  host: localhost
  port: 8983
  collection: mytest
  bulkSize: 500
  idColumnName: id

何がうれしいか?

他の output plugin と同様ですが、色々なリソースから取得したデータを Solr に一括でフィードすることが出来ます。例えば、embulk-input-jdbc と組み合わせることで、データベースに入っているレコードを Solr にフィードするバッチが簡単に用意することができます。embulk-input-jdbc にはWHERE句を指定する機能もあるので、例えば更新されたレコードだけフィードする、というような差分更新も簡単に実現できます。

embulk の素晴らしいところは、input と output をどのようにでも組み合わえることができるので、input プラグインさえあればどのようなデータソースでも Solr で検索できるようになることです。*1

一昔前のプロプライエタリな商用の検索エンジンでは、コネクターといっていかに多くのリソースに対応しているかが競争力の源泉の一つだったのです。なぜなら、そもそも検索したい対象のリソース(Oracle やら MySQL やら SharePoint やら ContentManager やら Documentum やら・・)につながらなければいけないし、SIer にコネクターを自作させるのもコスト的にも将来の保守的にも不安があったので、すでに製品に対応しているコネクターが用意されていれば当然そちらを購入していたわけです。もちろん、全てのリソースに対してプラグインがあるわけではないのですし、昔と今とでは OSS の受け入れ度も全く違うので一概には言えませんが、今やこんなに簡単に色々なリソースと繋がるなんて夢のようだなーと遠い目をしてしまうわけです。

embulk-parser-xml2 も公開しました

Solr と合わせて xml2 という parser プラグインも公開しました。これは、input で読み込んできた xml をパースしてフィールドと値を抽出して embulk で扱えるようにすることができるプラグインです。

https://github.com/yahoojapan/embulk-parser-xml2

embulk の parser にはすでに xml 用のプラグインが2つあるのですが、一方は DOM でパースしており大きな XML 文書は扱えず、もう一方は SAX パーサーですがサブエレメントを扱うことが出来ませんでした。例えば、以下のような XML があり、page タグを 1 文書として扱うとして設定したい場合、id タグと title タグは扱うことが出来たのですが、revision/timestamp や revison/text タグは扱うことが出来ませんでした。

<mediawiki>
  <page>
    <id>1</id>
    <title>title 1</title>
    <revision>
      <timestamp>2004-04-30T14:46:00Z</timestamp>
      <text>body text</text>
    </revision>
  </page>
  <page>
    <id>2</id>
    <title>title 2</title>
    <revision>
      <timestamp>2004-04-30T14:46:00Z</timestamp>
      <text>body text</text>
    </revision>
  </page>
</mediawiki>

このプラグインを利用することで embulk を使って、大きな XML 文書でかつ上記のようなサブエレメントが必要なドキュメントも、高速にパースして取り込むことができるようになります。例えば、Wikipedia のダンプを Solr に取り込ませたい場合、このプラグインを使うといい感じに読み込むことが出来ます!

ぜひこちらもご利用ください。

*1:inputプラグインの一覧は以下のブログにまとまっています。 http://qiita.com/hiroysato/items/da45e52fb79c39547f69#input%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3

Solr 6 新機能の紹介

IT、プログラミング Solr 検索エンジン

https://lucene.apache.org/solr/6_0_0/images/solr.svg

だいぶ時間が立ってしまいましたが、Solr 6 がリリースされました!というわけで、Solr 6 の新機能をドキュメントから調査してみました。調査する新機能は、yonik さんの以下のエントリを参考にしました。*1

http://yonik.com/solr-6/

Parallel SQL

https://cwiki.apache.org/confluence/display/solr/Parallel+SQL+Interface#ParallelSQLInterface-JDBCDriver

  • Solr で SQL が使える (select のみ、intsert / update / delete は対応しない)
    • 裏では Presto の SQL Parser を使って Streaming Expression (こちらも新機能、後述) に変換している
  • テーブル
    • テーブル名 = コレクション名
    • case insensitive
  • カラム
    • カラム名 = フィールド名
    • case sensitive
    • エイリアスをサポート、order by クラウスで参照できる
      • は利用不可
    • カラム名に score を指定することは LIMIT クラウスが含まれる場合のみ可

例1:techproducts コレクションのフィールド、manu と price を検索する

SELECT manu as mfr, price as retail FROM techproducts
  • Aggregation Model

    • Solr の SQL では、aggregation (結果のグルーピング) を2つの方法でサポートしている
      • Solr へのリクエスト時のパラメータで、どちらを利用するかを選択できる
    • map_reduct : ワーカーノードに送信する際にシャッフル (つまりソート)を行い、ワーカーノードで aggregation を行う。GROUP BY を行う対象のフィールドのカーディナリティ (値のバリエーション) に上限はないが、検索結果全体をネットワーク上に送信するコストがかかる点に注意が必要。
    • facet : JSON Facet API / StatsComponent を利用する方法。通常の検索と同様に Solr の検索で処理させる方法なので、ネットワークに送信されるのは集約された後の結果のみ。フィールドのカーディナリティが低い場合にはとても速い。
  • 設定

    • リクエストハンドラに、/sql と /stream 、/export を設定する (いずれもデフォルトでは暗黙的に設定されているので、solrconfig に書く必要はない)
    • SQL で使用するフィールドについて、docValues を設定する
  • JDBC Driver

    • SolrJ を JDBCDriver として利用できる
  • HTTP
    • /sql に対して、SQL を POST しても利用できる

例2:HTTP による POST

-bash-4.1$ curl --data-urlencode "stmt=SELECT id, price FROM techproducts WHERE popularity=1 LIMIT 100" http://ojt02.takumyos.ssk.ynwm.yahoo.co.jp:8983/solr/techproducts/sql?aggregationMode=facet
{"result-set":{"docs":[
{"price":19.95,"id":"F8V7067-APL-KIT"},
{"price":11.5,"id":"IW-02"},
{"EOF":true,"RESPONSE_TIME":6}]}}
  • 利用可能な表現
    • LIMIT
      • LIMIT が指定されていると score を得ることができる
      • LIMIT が指定されていると stored field なら field list に指定できる。unlimited の場合 docValues フィールドのみ利用できる
      • LIMIT が指定されていると indexed field なら order by に指定できる。unlimited の場合 docValues フィールドのみ利用できる
    • WHERE
      • = , () , OR , [ ] , NOT
    • ORDER BY
    • DISTINCT
    • Statistics
      • count / min / max / sum / avg
    • Group by
      • Having

メモ:まだ不安定な様子なので実際に利用するには程遠い

ざっと触ってみただけでも、以下の様な問題が有り、枯れていない印象です。(もしかしたら単にドキュメントが間違えているだけかもしれません・・w → Streaming Expression のドキュメントの間違いについては別のエントリにまとめます。)

  • WHERE id=apple とすると、正しくない結果が得られる (id は docvalues のフィールドではない)
  • WHERE price=[0 to 100] が利用できない (InvalidNumber エラーが出ている)
-bash-4.1$ curl --data-urlencode 'stmt=SELECT id, price FROM techproducts WHERE price="[0 to 100]" LIMIT 100' http://ojt02.takumyos.ssk.ynwm.yahoo.co.jp:8983/solr/techproducts/sql?aggregationMode=facet
{"result-set":{"docs":[
{"EXCEPTION":"java.util.concurrent.ExecutionException: java.io.IOException: --> http://172.21.234.168:7574/solr/techproducts_shard2_replica2/:Invalid Number: ","EOF":true,"RESPONSE_TIME":7}]}}

Streaming Expressions

https://cwiki.apache.org/confluence/display/solr/Streaming+Expressions

Streaming Expression は現状、実験的な API のため将来インターフェースが変更される場合があるそうですのでご注意ください

Streaming Expression では、並行に実行される異なるタスクの結果を結合することができる機能です。

例1:Stream Expression で検索している例。

-bash-4.1$ curl --data-urlencode 'expr=search(techproducts,q="*:*",fl="price", sort="price desc")' http://ojt02.takumyos.ssk.ynwm.yahoo.co.jp:8983/solr/techproducts/stream
  • search は export リクエストハンドラに依存しているので、sort と fl が指定されている必要がある。
  • sort に指定された項目は fl でも指定する必要がある。

指定可能な function

  • search : Solr で検索を行うファンクション、利用可能なパラメータに制限がある
  • jdbc : Stream で JDBC を使って Select を実行して結果を得る
  • facet : facet 検索を使って、バケットごとに集約する機能を提供する。
  • stats : 検索結果に対してシンプルな集約関数を提供する (sum/avg/min/max/count)
  • topics : pub/sub メッセージング。ユーザーはクエリを予め登録しておき、クエリに該当するする新規に登録されたか更新されたドキュメントを一度だけ返す。

指定可能な decorator

  • complement : クエリAとクエリBを指定し、A にはあるが Bに含まれない結果を出力する
  • daemon : 指定した間隔で繰り返しファンクションを実行する (例:あるコレクションAに対する検索結果をコレクションBに継続的に登録する、
  • innterJoin : DB の inner join に相当、右のStreamに存在する Left のデータを結合して出力する。 (2つのストリームを連結するフィールドでソートしておく必要がある)
  • intersect : Left の Stream に存在する RIght のデータを出力する。Left のデータと結合せず、Right のデータのみを出力する。(2つのストリームを連結するフィールドでソートしておく必要がある)
  • hashJoin : DB の inner join に相当、右のStreamに存在する Left のデータを結合して出力する。(2つのストリームがソートされている必要が無いが、メモリを多く利用する)
  • Merge : 2つ以上の複数の Strem を結合する。あらかじめ指定したフィールドでソートしておく必要がある。 (DBのUnion)
  • leftOuterJoin : DB の left outer join と同様に、指定した2つの結果をくっつけることができる (2つのストリームを連結するフィールドでソートしておく必要がある)
  • outerHashJoin : DB の right outer join に相当 (2つのストリームがソートされている必要が無いが、メモリを多く利用する)
  • parallel : 複数の worker ノードに指定したストリームを並列して処理させることができる
  • reduce : 共通のフィールドでグルーピングする。
  • rollup : 指定したフィールドで Steream をグルーピングし、集計を行う。 (sum / min / avg / max / count ) グルーピングするフィールドで予めソートしておく必要がある
  • select : 元のストリームに含まれるフィールドのサブセットや変更されたフィールドを出力する。(出力するフィールドのチョイス、rename、値のリプレイス)
  • top : 指定した N 件の結果を出力する。
  • unique : 指定したフィールドの値を基準にユニークなストリームを生成する
  • update : 指定したストリームを元に、インデックスの更新処理を行う。

Graph Traversal Query

https://cwiki.apache.org/confluence/display/solr/Other+Parsers#OtherParsers-GraphQueryParser

  • ファンクションクエリの一つ
  • 幅優先探索、cyclic aware (閉路をサポート?)
  • クエリパラメータの to と from に指定したフィールドの値を元に、ドキュメント間のリンクを構築する

注意:上記の cwiki のドキュメントにある、Example のグラフの絵が正しくない

制限:この機能は1つの Solr インスタンス内でしか結果をたどることが出来ません! 6.1 では Streaming Expression で複数の分散ノードでのグラフ検索がサポートされる予定です。

パラメータ

  • to : 入力エッジを示すフィールド名を指定
  • from : 出力エッジを示すフィールド名を示す
  • traversalFilter : クエリー、マッチしたノード(ドキュメント)をフィルターする条件を指定する (あるノードがマッチしなかった場合、その先のノードは探索されない)
  • maxDepth : ノードに許容されるルートノードからの距離(最大エッジ数)
  • returnRoot : ルートノードを結果に含めるかどうか (boolean)
  • returnOnlyLeaf : リーフ(incoming edge だけのノード)だけを返すかどうか (boolean)
  • useAutn : 幅優先探索のイテレーションごとにオートマトンをコンパイルするかどうかを指定する (boolean)

メモ

BM25 Scoring

  • Okapi BM25 がデフォルトになります。
  • これまでの TF-IDF を使いたい場合は、ClassicSimilarity を使ってね。

Filters for Real-Time Get

https://cwiki.apache.org/confluence/display/solr/RealTime+Get

  • Real-Time Get (リクエストハンドラー /get ) で fq をサポート。取得するドキュメントをフィルターすることができる

Cross Data Center Replication (CDCR)

https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=62687462

  • 複数のデータセンター間での、データのレプリケーション
  • active-passive シナリオのみを本バージョンではサポート
    • データの更新があった場合に、ソースとなるデータセンターから、ターゲットのデータセンター(複数)にレプリケーションする
    • その逆はない、ターゲット側で更新してもソースには反映されない
    • レプリケーション中も検索はどちらでも可能
    • ターゲットのデータセンターではデータが反映されるまでの遅延が数秒程度生じる
  • インデックスデータが disk に書き込まれてからレプリケーションは開始される (commit されてから)
  • すぐにレプリケーションを開始するか、スケジュールするかは選択することができる
  • それぞれのシャードリーダーどうしがレプリケーションを行う
  • コネクションの切断や帯域の劣化などに耐えられるように設計されている、またコミュニケーションの最適化のためにバッチアップデートもサポートする
  • 更新分のデータの一貫性は保証するが、インデックス全体の一貫性は保証しない (気にしない)
    • つまり、CDCR を開始する前にすでに登録されていたインデックスはそのまま保持される
  • コレクション単位で設定する
  • ソースの Solr クラスタからターゲットの zookeeper アンサンブルが見えるようになっている必要がある
  • 高頻度のアップデートがある環境で builk-load する用途には向いていない場合がある (帯域による) 。その場合は、あらかじめ bulk-load して同期した後に、CDCR を有効にすると良い。
  • 使用可能な帯域の指定や制限などはできないが、batch-size やスケジュールである程度コントロールできそう

メモ

  • 単純なレプリケーションだけでなくインデックスのマイグレーションに使えるかも?
    • Solr の構成が異なっても問題ないか? (シャード数、レプリカ数)
    • on the fly でレプリケーション先を指定できるか? また、解除できるか?
    • 現在登録されているデータのレプリケーションが完了したことを簡単に検知できるか? (batch update モード?)

おすすめ書籍

[改訂新版] Apache Solr入門 ~オープンソース全文検索エンジン (Software Design plus)

[改訂新版] Apache Solr入門 ~オープンソース全文検索エンジン (Software Design plus)

  • 作者: 大谷純,阿部慎一朗,大須賀稔,北野太郎,鈴木教嗣,平賀一昭,株式会社リクルートテクノロジーズ,株式会社ロンウイット
  • 出版社/メーカー: 技術評論社
  • 発売日: 2013/11/29
  • メディア: 大型本
  • この商品を含むブログ (8件) を見る

検索エンジン自作入門?手を動かしながら見渡す検索の舞台裏

検索エンジン自作入門?手を動かしながら見渡す検索の舞台裏

*1:リリースノートを見ると、ほぼ全てカバーできているみたいでしたが

Solr 開発環境構築手順

IT、プログラミング Solr 検索エンジン

よしだです。今日は Solr のパッチを作ったり機能追加をするために必要な開発環境の構築手順を公開してみたいと思います。subversion からのチェックアウトからeclipseの環境構築までをカバーします。

前提条件

  • 以下のソフトウェアは導入、設定済みとします。

java 8

$java-version
javaversion"1.8.0_51"
Java(TM)SERuntimeEnvironment(build1.8.0_51-b16)
JavaHotSpot(TM)64-BitServerVM(build25.51-b03,mixedmode)

ant

$ant-version
ApacheAnt(TM)version1.9.3compiledonDecember232013

svn

$svn--version
svn,version1.8.8(r1568071)
 compiledMar292014,20:04:07onx86_64-apple-darwin13.1.0

事前準備、フォルダの作成

$ cd /
$ mkdir app
$ sudo chown me:staff app
$ mkdir app/solr

チェックアウト

SVN は以下のページを参考に、アノニマス(読み取り専用)のURLを指定します。

http://lucene.apache.org/solr/resources.html

ポイントは、チェックアウト元のURLを dev ではなく、dev/trunk にすること。公式サイトでは dev までになっていますが、そのままでは branch 等含まれるのでひどく時間がかかりますし、全ては不要だと思いますので、ご注意ください。

$ svn checkout http://svn.apache.org/repos/asf/lucene/dev/trunk/solr

コンパイル

$ cd solr
$ ant ivy-bootstrap
$ ant compile

server を作成

server をビルドして、動作確認します。server をビルドすると、設定ファイル等を含む、Solr が配布されている状態にビルドされますので、そのまま動作確認が可能な状態になります。

以下の cd 後のパスが、ちょっとわかりにくですが、/app/solr/solr となります。

$ cd solr
$ ant server

Solr の起動

以下のコマンドを実行すると、Solr がバックグラウンドで起動します。停止は bin/solr stop 。

$ bin/solr start

eclipse で開発できるようにする

eclipse にインポートができるように、設定ファイルを生成します。

参考: https://wiki.apache.org/solr/HowToContribute#Notes_for_Eclipse

$ cd ../
$ ant eclipse

その後、eclipse から /app/solr を既存のプロジェクトとしてインポートする。インポート時に、「コピーする」からチェックを外すことを忘れないこと。

※ ちなみに eclipse の subversion プラグインは、subclipse がおすすめ。subclipse では .svn フォルダを見つけると、自動的に subversion で管理されているプロジェクトとしてひも付けてくれる。subclipse を使えば上記手順後、eclipse で subversion の比較など操作ができるようになる。subversion プラグインで有名ドコロのもう一つ、subversive では、できません。

おわりに

Solr や OSS のコードを読みたい、パッチを書いてみたい、機能を追加してみたいと思っても、しょっぱなの環境構築で躓くことって結構あると思います。Solr について書いてみましたが、他の OSS でも似たような手順だと思うので、色々と参考になると思いました。(apache の svn ではなく Github だとまたちょっと違うのですが、まあ似たようなもんですw )

おまけ : start.jar で起動したい

古い Solr では、起動するときに start.jar を直接呼んでいたのですが、バージョン 5 からは標準的には bin/solr というスクリプトが導入され、bin/solr start で起動するようになっています。旧バージョンの起動方法 java -jar start.jar だけでは起動しないようになっています。だたし、以下のようにオプションをつけると起動します。

java -jar start.jar --module=http

この方法だと、コンソールにログが出てくるので、特に tail の無い windows では開発に便利ですよね。

参考書籍

[改訂新版] Apache Solr入門 ~オープンソース全文検索エンジン (Software Design plus)

[改訂新版] Apache Solr入門 ~オープンソース全文検索エンジン (Software Design plus)

  • 作者: 大谷純,阿部慎一朗,大須賀稔,北野太郎,鈴木教嗣,平賀一昭,株式会社リクルートテクノロジーズ,株式会社ロンウイット
  • 出版社/メーカー: 技術評論社
  • 発売日: 2013/11/29
  • メディア: 大型本
  • この商品を含むブログ (8件) を見る

Solr 5: Troubleshooting and Maintenance

Solr 5: Troubleshooting and Maintenance

勉強会メモ - 第17回 Lucene/Solr勉強会

IT、プログラミング Solr 検索エンジン

取り急ぎ、公開しておきます!

https://solr.doorkeeper.jp/events/32633

タイトル:「Solrの対話型ゲームへの応用」

株式会社リクルートテクノロジーズ 大杉様 / 株式会社NTTデータCCS 鈴木

  • 脳内彼氏具現化計画 (脳カレXGAME) http://atl.recruit-tech.co.jp/noukare_game/

  • 頭脳がSolrベース

  • 人工無能的な?
  • 検索の過程にたどり着くまでは一般的にストレスだが、聞く・対話を楽しむゲームでは楽しみである
  • 普通の会話は1000パターン用意しても、検索結果0件の割合は約50%
  • 一方ゲームに絞ると100パターンまで減らすことができる
  • 裏でフラグの状態を保存している
  • 入稿ファイル形式:
  • エクセルだけで会話コンテンツを作成
  • フラグ管理や出力画像・テキスト全て開発可能

ここから鈴木さん

  • 利用しているところ
  • LINE公式アカウント「パン田一郎」
  • 脳カレ・脳カレ・ゲーム
  • その他色々
  • 使い方
  • 応答データのストアと検索
  • 応答データは数万程度
  • Master - Slave 構成、500QPS 以上
  • 工夫
  • J-POSフィルタ、品詞のフィルタを限定する、例えば名詞だけ抽出する
  • 助動詞の「ない」という言葉も有効なので残してある (一般的な検索では助動詞は使わないが)
  • 例)面白くない
  • N-Gramフィールド (N=5以上)、特定の繰り返しワードなどに対応
  • 例)バカバカバカバカ

タイトル:「Lucene/Solr Revolution 2015参加レポート」

ヤフー株式会社 メディアカンパニー 検索事業本部 サーチテクノロジー部 宋 賢佑様

www.slideshare.net

  • 注目セッション:Learning to Rank in Solr
  • Bloombergニュース検索
  • ML の必要性
  • 一日800万サーチ、4億の記事
  • 検索クエリに対して適合率が高い検索結果を返したい、手動チューニングはコストが高い、ドキュメントの更新が常に発生する
  • Learning to Rank、MLR
  • Implicit Data と Explicit Data を元に Feature を抽出し Rank Model を作成する
  • Featrue は特徴点のこと(点数)
  • Metrics でランキングの良し悪しを判定
  • 静的な計測方法 Presicion / Recall / F-score
  • オンライン CTR / Time to first click / 滞留時間
  • 学習方法
  • Rank SVM など

  • これらのノウハウを LTR プラグインとしてまとめた (未公開)

  • 手動でチューニングしない
  • リレバンシーの改善
  • レイテンシ維持

  • 今後のSolr

  • Analytics
  • SQL like interface
  • ML
  • NLP
  • などなど

タイトル:「Apache Lucene/Solrによる形態素解析の課題とN-bestの提案」

ヤフー株式会社 CTO室 大須賀 稔様

www.slideshare.net

  • アナライザのしくみ (まえふり)
  • 文字フィルタ、トークナイザー、トークンフィルターの3ステップ
  • 形態素解析とNgramは相反する長所短所をもつ
  • 検索結果の評価の方法
  • 適合値、最現地、F値(F-measure)

  • 形態素解析では検索漏れが多く、N-Gram ではノイズが多すぎる

  • N-Gramの併用による課題:ノイズの大量発生、インデックス量
  • JapaneseTokenizerのモードによる解決:normalモード、searchモード、extendedモード
  • 課題:意図しない分割をされるパターンがある、1つのパターンしか出力されないので複数の意味が取れるパターンに対応できない

  • N-best の実装

  • 解釈によって異なる複数のパターンでの分割、複合語の分割を可能にし、再現率の向上を目指す
  • JapaneseTokenizerにN-best機能を追加する、既存のモードと併用、

  • N-Gram よりも意味がある細かい単語で分割が可能。

  • パッチ公開済み https://issues.apache.org/jira/plugins/servlet/mobile#issue/LUCENE-6837

タイトル:「U-NEXTにおけるSolr活用事例」

株式会社U-NEXT システム開発部 秋穂 賢 様(@ken_aio)

  • U-Next ビデオ・オンデマンドの会社
  • フリーワード検索(インクリメンタルサーチ)、ユーザー毎のレコメンドデータのキャッシュ

  • レコメンドのキャシュに使った理由は、ユーザー毎のレコメンドが Redis では難しかったため。

後輩の席に行ったら、このブログのページが開いていた・・

日記

どうも!ご無沙汰しております。二ヶ月以上書いておりませんでした。

ちょうど2ヶ月ほど前に参画したプロジェクトが忙しくて、なかなかブログを書く気力を持つことができませんでした。気力があっても、あらたなネタを吸収できる余裕がなく書くことも作れないような状況でございます。毎回参加していた Elasticsearch の勉強会も2回もスキップしてしまい、新ロゴのステッカーも未入手です。。もし、技術ネタを楽しみにしていてくれる方がいらっしゃったら、今日はそういった状況でございますので、いつもの技術ネタは上げられません、すいません。

で、表題の件ですが、今日仕事中にちょっとわからないことがあって、よく知っている後輩のところに質問に行ったんですよ。普段の仕事はパッケージと言われるソフトウェアを中心にしたシステムの開発をしているのですが、私があまりやってこなかったソフトで、よく知っている後輩がおりまして。

彼のところへ行って「これってできるんだっけー?」というような質問をしたところ、彼は「ちょっとやってみないとわからないですね。少し待ってください。」といって、手元のPCで作業を始めました。私はその作業を見つつ、開きっぱなしになったブラウザーをぼーっと眺めておりました。

そうすると、たくさん開いたタブの中に見慣れたファビコンがいるではありませんか。ええ、当ブログのファビコンでした。ちゃんとファビコン設定しているとこんないいことがあるんですね、はてなさんどうもありがとうございました(ガクガク

ブログをやっていることを秘密にしているわけでもなく、やましいことを書いているわけでもないので、身バレしようが全く全く全く問題はないのですが、まぁびっくりしました。有名ブロガーの皆様はこんなことは日常茶飯事なんでしょうがね!

後輩に質問した内容と結果? それはどうでもいいですね。 以上、よろしくお願いします。

その後輩へ、俺か?と思ったら名乗り出なさいw