関口宏司のLuceneブログ

OSS検索ライブラリのLuceneおよびそのサブプロジェクト(Solr/Tika/Mahoutなど)について
<< キーフレーズ抽出ツール KEA を Lucene 上で実装する | main |
Solr でランキング学習を体験する

最近俄に(?)脚光を浴びてきた「ランキング学習(Learning-to-Rank、以下LTRと略すこともある)」をSolrで試す方法を紹介しよう。

Solrでランキング学習というと、まもなくリリースされる Solr 6.4.0 に含まれる SOLR-8542 を思い浮かべる方もいるかもしれない。しかしここでは、「第19回 Lucene/Solr 勉強会」でシーマークの山本社長が発表したNLP4Lを使った方法を採り上げたい。以下の理由からSOLR-8542よりはるかに使い方が簡単だからだ。

また、NLP4Lはランキング学習の論文で紹介される一般的な特徴であるTF、IDF、TF*IDFなどが扱えるのに対し、SOLR-8542はこれらの特徴は扱えない(扱う予定もなさそう)。さらにSOLR-8542はモデルを利用する部分でSolrに依存するところが大きいが、NLP4Lでは大事な部分はLuceneレベルで行われ、LTRの主要な部分の実装がコンパクトである。したがってElasticsearch対応も比較的簡単である。もちろんSOLR-8542の方が優れている部分もあり、使用する特徴をSolrのクエリ式で書けるところはNLP4Lよりも柔軟で優位性があるといえる。

LTRの学習データについて

LTRは教師あり学習を基本とする。教師データのイメージは、「あるクエリについてそれぞれの文書がどのくらい関連しているか」というラベル(NLP4Lではrelevance degreeと呼んでいる)がつけられている一連のレコードである。この形式のデータを学習するアルゴリズムはPointwiseアプローチと呼ばれる。他にも「あるクエリについて文書ペアがどちらがより関連度が高いか」というラベルがついたデータを扱うPairwise、「あるクエリについて文書集合が関連度順にどのようにリストされるか」というラベルがついたデータを扱うListwiseがある。

前述の3番目の「教師データの準備方法」について、NLP4Lでは付属の「アノテーションGUI」を使った方法と、「アクセスログ(aka クリックログ、NLP4Lでは特別に「インプレッションログ」と呼んで通常のアクセスログと区別している)からクリックモデルを計算して関連度を自動算出する」方法が用意されている。本記事では説明の簡略化のため前者の「アノテーションGUI」を使った方法を採り上げる。しかし本番システムで人手でアノテーションを行うのはなにかと大変だ。本記事を読んでランキング学習の手順を理解したら、ぜひ後者の「アクセスログからクリックモデルを計算して関連度を自動算出する」方法に挑戦していただきたい。

以下、NLP4Lでのランキング学習の手順の概要である。この順番で以降説明を進める。

  1. Solr 6.3.0 のインストール
  2. LTRのためのSolrプラグインのビルドと設定
  3. livedoor ニュースコーパスの登録
  4. NLP4Lのインストールと起動および設定
  5. 教師データの作成
  6. 特徴抽出
  7. ランキング学習
  8. モデルのデプロイ
  9. ランキング学習モデルを使ったリランキングの実際

前述の通り、NLP4Lには詳細なLTRのためのマニュアルが付属するのでここであらためて記事にする必要もないかもしれないが、本記事では対象文書セットとしてlivedoorニュースコーパスを用いることで、一連の操作方法をより具体的に説明している。興味のある方は、下記手順通りにインストールと設定を進めれば、Solrでランキング学習の実際を体験することができる。より詳細を知りたい場合にはNLP4Lのマニュアルをご覧いただきたい。

Solr 6.3.0 のインストール

適当なディレクトリにてSolr 6.3.0(本記事執筆時の最新)をダウンロード、展開する。本記事では/opt/nlp4l/solr-6.3.0ディレクトリにSolrを展開するとして話を進める。

$ pwd
/opt/nlp4l
$ wget http://ftp.tsukuba.wide.ad.jp/software/apache/lucene/solr/6.3.0/solr-6.3.0.tgz
$ tar xvzf solr-6.3.0.tgz

Solrを起動し、collection1という名前のコアを作成する。

$ cd solr-6.3.0
$ ./bin/solr start
$ ./bin/solr create_core -c collection1 -d sample_techproducts_configs

LTRのためのSolrプラグインのビルドと設定

適当なディレクトリにてgithubで公開されているNLP4L/solrプロジェクトをダウンロード、ビルド、Solrにデプロイする。

$ pwd
/somewhere/NLP4L
$ git clone https://github.com/NLP4L/solr.git
$ cd solr
$ mvn package
$ cp target/nlp4l-solr-1.1-SNAPSHOT.jar /opt/nlp4l/solr-6.3.0/server/solr-webapp/webapp/WEB-INF/lib
 

NLP4L/solrはtypesafe社のconfigライブラリが必要なので、以下のように入手、ビルド、Solrにデプロイする。

$ cd /somewhere
$ wget https://github.com/typesafehub/config/archive/v1.3.1.tar.gz
$ tar xvzf v1.3.1.tar.gz
$ cd config-1.3.1
$ sbt package
$ cp config/target/config-1.3.0-20170120T044439.jar /opt/nlp4l/solr-6.3.0/server/solr-webapp/webapp/WEB-INF/lib
 

Solrに付属のJettyのwebapp設定を次のように行う。

$ cd /opt/nlp4l/solr-6.3.0
$ vi server/solr-webapp/webapp/WEB-INF/web.xml
 
  
    fileReceiver
    org.nlp4l.solr.servlet.FileReceiver
    
      root_path
      /opt/nlp4l/solr-6.3.0/server/solr/collection1
    
  

  
    fileReceiver
    /nlp4l/receive/file
  
 

また、選択可能な特徴を以下のようにJSON設定ファイルに用意する。

$ vi server/solr/collection1/conf/ltr_features.conf
 
{
  "features": [
    {
      "name": "TF in title",
      "class": "org.nlp4l.solr.ltr.FieldFeatureTFExtractorFactory",
      "params": { "field": "title" }
    },
    {
      "name": "TF in body",
      "class": "org.nlp4l.solr.ltr.FieldFeatureTFExtractorFactory",
      "params": { "field": "body" }
    },
    {
      "name": "IDF in title",
      "class": "org.nlp4l.solr.ltr.FieldFeatureIDFExtractorFactory",
      "params": { "field": "title" }
    },
    {
      "name": "IDF in body",
      "class": "org.nlp4l.solr.ltr.FieldFeatureIDFExtractorFactory",
      "params": { "field": "body" }
    },
    {
      "name": "TF*IDF in title",
      "class": "org.nlp4l.solr.ltr.FieldFeatureTFIDFExtractorFactory",
      "params": { "field": "title" }
    },
    {
      "name": "TF*IDF in body",
      "class": "org.nlp4l.solr.ltr.FieldFeatureTFIDFExtractorFactory",
      "params": { "field": "body" }
    }
  ]
}

また、solrconfig.xmlを以下のように編集する。

$ vi server/solr/collection1/conf/solrconfig.xml

標準の /select リクエストハンドラのdefaultsパラメータに以下を追加する。

       edismax
       title body

NLP4L-LTRからの特徴抽出リクエストに応答するためのリクエストハンドラを以下のように設定する。


  
    ltr_features.conf
  

最後に、PRankクエリを呼び出すPRankQParserPluginを次のように設定する(PRank以外にRankingSVMが選択可能)。


  
    collection1/conf/ltr_features.conf
    collection1/conf/ltr_model.conf
  

またSolrあるあるであるが、Elevation Component関連の設定もここで削除しておこう。

livedoor ニュースコーパスの登録

livedoor ニュースコーパスをSolrに登録するために、まずスキーマを設定する(APIを通じてスキーマ変更するのが推奨だが、面倒なのでエディタで編集してしまう)。

$ vi server/solr/collection1/conf/managed-schema
   
   
   

   
   

   

   url

されに不要なcopyField設定は取り除いておく。ここでSolr設定の変更を有効化するためにコアのリロードまたは再起動を行う。

そしてlivedoor ニュースコーパスを入手し、Solrに登録する。

$ cd /somewhere
$ wget http://www.rondhuit.com/download/livedoor-news-data.tar.gz
$ tar xvzf livedoor-news-data.tar.gz
$ /opt/nlp4l/solr-6.3.0/bin/post *.xml

NLP4Lのインストールと起動および設定

NLP4L/nlp4l プロジェクトを github から以下のように入手し起動する。

$ cd /somewhere/NLP4L
$ git clone https://github.com/NLP4L/nlp4l.git
$ cd nlp4l
$ cp conf/application.conf.sample conf/application.conf
$ vi conf/application.conf
$ ./activator run

そしてWebブラウザから http://localhost:9000/ にアクセスする。NLP4L-LTRというメニューを選び、画面上部に表示されるメニューのConfigをクリックする。そして<<New>>リンクをクリックすると、新しいConfig設定をするように促される。次の表を参考に設定する。

パラメータ名説明本記事での設定値
Nameこの設定の名前test
Annotation Typeアノテーションの種別。現在はpointwiseしか選べない。これは現在のNLP4Lが学習アルゴリズムがPointwiseのものしか扱えない、という意味ではない。実際、NLP4LがサポートしているRankingSVMはPairwiseであるが、Pointwise形式のデータを内部でPairwiseに変換している。pointwise
Relevance Degreepointwiseにて人手でつける星の数をいくつからいくつまでとするか。0 to 3
Trainer Factory Class学習アルゴリズムのファクトリクラス名を指定する。PRankTrainerFactoryまたはRankingSVMTrainerFactoryが選べる。 org.nlp4l.ltr.support.procs.PRankTrainerFactory
- settings学習の繰り返し数。{ "numIterations": 2000 }
Search URL教師データ作成時、人手でアノテーションする際、連携先となるSolrのURL。http://localhost:8983/solr/collection1/select?q=${query}&wt=json&hl=true&hl.fl=title,body&f.body.hl.snippets=3&hl.simple.pre=<b style="background-color:yellow">&hl.simple.post=</b>
Feature Extract URL特徴抽出する際の連携先となるSolrのURL。solrconfig.xmlに設定したリクエストハンドラのURLを記載する。http://localhost:8983/solr/collection1/features
Feature Extract Config特徴抽出時に参照する、Solr側に配置されたJSON設定ファイル名。ltr_features.conf
Document Unique FieldSolrのユニークキーのフィールド名。url
Document Title FieldSolr文書のタイトルフィールド名。人手によるアノテーション実施時に、タイトルとして画面表示されるフィールド名を指定する。title
Document Body FieldSolr文書の本文フィールド名。人手によるアノテーション実施時に、本文として画面表示されるフィールド名を指定する。 body
Deployer Factory Class学習して得たモデルファイルをSolrにデプロイするときに使用するクラスのファクトリ。org.nlp4l.ltr.support.procs.HttpFileTransferDeployerFactory
- settings上記クラスのURL。{ "deployToUrl": "http://localhost:8983/solr/nlp4l/receive/file", "deployToFile": "conf/ltr_model.conf" }

[Save]ボタンをクリックして[Load]をクリックすると、画面上部にtestという名前のConfigがロードされたことが示され、Query、Annotation、Feature、Trainingというメニュー項目が現れる。

教師データの作成

教師データを作成する場合はQueryまたはAnnotationメニューを使う。なお前述の通り、本記事ではアノテーションGUIを使った教師データの作成方法を説明する。アクセスログ(インプレッションログ)からクリックモデルを計算することで教師データを安価に用意したい場合は、Queryメニューの[Import]ボタンをクリックしてログファイルをロードする。

Queryメニューにはファイルを選択するボタンがあり、これをクリックするとクエリ一覧が記載されたテキストファイルを選べるようになる。このテキストファイルには1行1クエリを記載しておく。このファイルをロードすると、下図のようにクエリが表示される。

LTR-QueryList

このクエリのリンクをクリックすると連携先のSolrにてクエリが実行され、Annotation画面に結果が表示される。この画面ではSearchテキストボックスに選択したクエリが表示されているが、Queryメニューから始めなくても、Annotationメニューを選んでこのSearchテキストボックスに直接クエリを入れても同じである。

LTR-Annotation

Annotation画面にて各クエリと返された文書の関連度を考えながら、右側に表示されている星の数を適切に選んでいく。1画面分終わったら、[Save]ボタンで保存し、[Next]で次のクエリに進む。一通り終了したら次のステップである特徴抽出に進む。

特徴抽出

Featureメニューを選択する。すると下図のようなプログレスバーが現れる。[Extract]で特徴抽出が開始するが、すでにプログレスバーが緑色になっているときは、まず[Clear]ボタンをクリックしてから[Extract]を行う。終了するとDONEと表示される。

LTR-FeatureExtraction

ランキング学習

Trainigメニューを選択し、左側にある<<New>>をクリックする。するとSolrに配置した設定ファイル(ltr_features.conf)にしたがって特徴を選ぶチェックボックスが現れる。このチェックボックスで適当に特徴を選んで[Start]をクリックする。ここでも学習の進行状況がプログレスバーで示され、終了すると下のようにモデルファイルの内容が表示される。ここではPRankを選択したので、各特徴に対する重みと、3つの閾値(星の数を最大3にしたことに由来)が返される。

{
  "model" : {
    "name" : "prank",
    "type" : "prank",
    "weights" : [ {
      "name" : "TF in title",
      "weight" : -113
    }, {
      "name" : "TF in body",
      "weight" : -14
    }, {
      "name" : "IDF in body",
      "weight" : -322.44384765625
    } ],
    "bs" : [ -2818, -2374, 6450 ]
  }
}

モデルのデプロイ

ランキング学習が終了すると[Deploy]ボタンが表示されるので、これをクリックすることで連携先のSolrにHTTPで転送される。

LTR-Model

Solr側ではこの学習モデルを有効化するために、コアのリロードが必要である。Solrの管理画面からコアのリロードを行うのが簡単だ。

ランキング学習モデルを使ったリランキングの実際

NLP4L-LTRはSOLR-8542とは異なり、Solr標準のリランクを使って呼び出すのでrq={!rerank …}パラメータを利用する。前述のsolrconfig.xmlに設定したprank queryParserを呼び出すには次のように検索を実行する。

http://localhost:8983/solr/collection1/select?indent=on&q=社会人 学生&rq={!rerank reRankQuery=$rqq}&rqq={!prank}社会人 学生&debugQuery=on

Solr標準のリランクは、(前述のsolrconfig.xmlの設定にしたがい)最初に通常のedismaxクエリを実行し、次に上位の200クエリ(reRankDocsのデフォルト)についてランキング学習モデルに基づいた再ランキングを行う。デバッグ情報のスコア詳細欄を見ると最初の2行は次のようになっている。

14.37461 = combined first and second pass score using class org.apache.solr.search.ReRankQParserPlugin$ReRankQueryRescorer
  10.37461 = first pass score

最初の行は2段階クエリのスコアの和が14.37461になっていることを示し、次の行は第1段階のクエリ(ここでは通常のedismax)のスコアが10.37461であることを示している。3行目以降はedismaxのスコア詳細なのでここではスキップしよう。

第2段階のクエリ、つまりPRankのクエリで計算したスコア合計は2.0であり、その詳細は下記のブロックで示されている。

  2.0 = second pass score
    2.0 = is the index of bs(-2818.0,-2374.0,6450.0) > -2338.074707 sum of:
      -113.0 = weight: -113.0 * feature: 1.0 sum of:
        0.0 = no matching terms
        0.0 = no matching terms
        1.0 = freq: 1
      -84.0 = weight: -14.0 * feature: 6.0 sum of:
        2.0 = freq: 2
        3.0 = freq: 3
        1.0 = freq: 1
      -2141.0747 = weight: -322.44385 * feature: 6.640147 sum of:
        2.762864 = log(numDocs: 7368/docFreq: 465)
        0.55211145 = log(numDocs: 7368/docFreq: 4242)
        3.3251717 = log(numDocs: 7368/docFreq: 265)

2.0というスコアは2倍(reRankWeightのデフォルト)され4.0となり、最終スコア合計が14.37461となる。2.0というスコアはどうやって計算されたかというと、モデルで与えられた重みを使って計算した結果が-2338.074707となるが、これは境界値の[-2374.0,6450.0]の範囲内にあるため2.0となる。

まとめ

livedoorニュースコーパスはフィールド数、文書数とも少ないので十分な教師データを作るのが難しいが、実運用されているフィールド数、文書数とも大きなデータにおいて、ランキング学習は通常のSimilarityが算出するスコアをより良く改善することが期待できる。ぜひ試していただきたい。

| 関口宏司 | 機械学習 | 13:49 | comments(3) | trackbacks(0) |
詳しい記事ありがとうございます。参考にさせていただきます。

SolrCloudの場合、コアのディレクトリ名がcollection1_shard2_replica1のように動的に生成されると思うのですが、これに対応したroot_pathの指定は可能でしょうか?
また、Annotation画面はtitle, bodyというフィールド名を変更したり、画像を表示したりできるのでしょうか?
| sc | 2017/01/24 9:22 PM |
特徴を設定するファイルや生成したモデルファイルを無理にconfディレクトリに置こうとすると上記のような設定になりますが、これはQParserPluginがSolrのリソースローダーにアクセスできないことから来ています。これらのファイルを${SOLR}/server/resources/ に置くようにすればいいのではないでしょうか。

Annotation画面でのフィールド姪は、記事中表のtitleやbodyを、myTitleやmyBodyなどとご自身のフィールド名に合わせて設定できます。画像は表示できないです。タイトルと本文だけからアノテーションしてもらう必要があります。
| 関口 | 2017/01/25 7:34 AM |
ありがとうございます。
フィールド名、普通に設定できましたね。失礼しました。
| sc | 2017/02/06 4:33 PM |









http://lucene.jugem.jp/trackback/484
+ Solrによるブログ内検索
+ PROFILE
 123456
78910111213
14151617181920
21222324252627
28293031   
<< May 2017 >>
+ LINKS
検索エンジン製品 - 比較のポイント
商用検索エンジンを購入した企業担当者は読まないでください。ショックを受けますから・・・
>>製品比較 10のポイント
+ Lucene&Solrデモ
+ ThinkIT記事
+ RECOMMEND
Apache Solr入門 ―オープンソース全文検索エンジン
Apache Solr入門 ―オープンソース全文検索エンジン (JUGEMレビュー »)
関口 宏司,三部 靖夫,武田 光平,中野 猛,大谷 純
+ RECOMMEND
Lucene in Action
Lucene in Action (JUGEMレビュー »)
Erik Hatcher,Otis Gospodnetic,Mike McCandless
FastVectorHighlighterについて解説記事を寄稿しました。
+ RECOMMEND
+ SELECTED ENTRIES
+ RECENT COMMENTS
+ RECENT TRACKBACK
+ CATEGORIES
+ ARCHIVES
+ MOBILE
qrcode
+ SPONSORED LINKS