関口宏司のLuceneブログ

OSS検索ライブラリのLuceneおよびそのサブプロジェクト(Solr/Tika/Mahoutなど)について
スポンサーサイト

一定期間更新がないため広告を表示しています

| スポンサードリンク | - | | - | - |
Solrを使って専門用語抽出

Solrを使って簡単に専門用語抽出する方法を紹介しよう。

専門用語とは?

専門用語」とは、Wikipediaによれば、「ある特定の職業に従事する者や、ある特定の学問の分野、業界等の間でのみ使用され、通用する言葉・用語群」である。そこで本記事では、ある特定の分野の文書が登録されたインデックスと、別の分野の文書が登録されたインデックスを比較し、互いに相手方のインデックスに含まれない単語集合を表示することで専門用語を抽出することにする。

Solrとインデックスの準備

ここで紹介する方法はSolr 1.4 以降であれば動作する(はず)。Solrを持っていない人はダウンロードして用意しよう。そして下記のschema.xmlを指定してSolrを起動する。

<?xml version="1.0" encoding="UTF-8" ?>
<schema name="example" version="1.5">
  <types>
    <fieldType name="string" class="solr.StrField" sortMissingLast="true" omitNorms="true"/>
    <fieldType name="int" class="solr.TrieIntField" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
    <fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/>
    <fieldType name="date" class="solr.TrieDateField" omitNorms="true" precisionStep="0" positionIncrementGap="0"/>
    <fieldType name="text_ja" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="false">
      <analyzer>
        <tokenizer class="solr.JapaneseTokenizerFactory" mode="search"/>
        <filter class="solr.JapaneseBaseFormFilterFactory"/>
        <filter class="solr.CJKWidthFilterFactory"/>
        <filter class="solr.JapaneseKatakanaStemFilterFactory" minimumLength="4"/>
        <filter class="solr.LowerCaseFilterFactory"/>
      </analyzer>
    </fieldType>
  </types>

  <fields>
    <field name="url" type="string" indexed="true" stored="true" required="true" />
    <field name="cat" type="string" indexed="true" stored="true"/>
    <field name="date" type="date" indexed="true" stored="true"/>
    <field name="title" type="text_ja" indexed="true" stored="true"/>
    <field name="body" type="text_ja" indexed="true" stored="false" multiValued="true"/>
  </fields>

  <uniqueKey>url</uniqueKey>
</schema>

文書データはここではlivedoorニュースコーパスを用いる。以下のようにwgetでlivedoorニュースコーパスを入手して展開しておく。

$ wget http://www.rondhuit.com/download/livedoor-news-data.tar.gz
$ tar xvzf livedoor-news-data.tar.gz

そしてSolrを起動して展開して得られたファイルのうちひとつ(例としてここでは「独女通信(dokujo-tsushin.xml)」をSolrに登録する。

$ ./post.sh dokujo-tsushin.xml
TermsComponentで単語リストを取得

次に、SolrのTermsComponentを使ってインデックスから単語一覧を取得する。次のcurlコマンドを実行すると、bodyフィールドでの使用頻度の多い順に上位1万語の単語一覧が得られる。

$ curl "http://localhost:8983/solr/collection1/terms?terms.fl=body&terms.limit=10001&omitHeader=true&wt=json&indent=true" | tail -n 10001|head -n 10000|cut -d , -f1|cut -d ¥" -f2 > dokujo-tsushin.txt
$ head -n 30 dokujo-tsushin.txt 
が
する
た
て
で
と
に
の
は
を
も
だ
いる
ない
ある
こと
から
なる
れる
か
という
人
う
や
です
ます
よう
ん
たい
思う

headコマンドで上位30位の頻出単語を表示しているが、前掲のschema.xmlファイルを見ていただくとわかるとおり、ストップワードの処理を一切していないので、およそ検索には役に立たない(そして専門用語でもない)単語が並んでいるのがわかるだろう。

次に異なる分野の文書を登録して同様に単語一覧を表示する。そのためにここでいったんSolrを停止してインデックスを削除し、再度起動して別の分野の文書(ここでは例として「スポーツウォッチ(sports-watch.xml)」)を登録する。そして同様にTermsComponentを使って単語一覧を得る。

$ ./post.sh sports-watch.xml
$ curl "http://localhost:8983/solr/collection1/terms?terms.fl=body&terms.limit=10001&omitHeader=true&wt=json&indent=true" | tail -n 10001|head -n 10000|cut -d , -f1|cut -d ¥" -f2 > sports-watch.txt
$ head -n 30 sports-watch.txt 
の
は
する
た
に
が
で
と
を
て
だ
日
も
いる
ない
れる
なる
から
ある
こと
か
という
です
ます
ん
その
日本
1
選手
語る
2つの単語集合を比較する

最後に2つの単語集合を比較して差分を表示するプログラムを書く。ここでは以下のような簡単なScalaプログラムを作成した。

package terms

import scala.io.Source

object TermsExtractor {

  def main(args: Array[String]): Unit = {
    val set1 = termsSet("/Users/koji/work/ldcc/dokujo-tsushin.txt")
    val set2 = termsSet("/Users/koji/work/ldcc/sports-watch.txt")
    
    println(set1 &~ set2)
    println(set2 &~ set1)
  }

  def termsSet(file: String): Set[String] = {
    val src = Source.fromFile(file, "UTF-8")
    var result : Set[String] = Set()
    try{
      src.getLines.foreach{ line: String =>
          result = result + line
      }
      result
    }
    finally {
      src.close
    }
  }
}

実行すると次のように2行の出力が得られる。1行目は「独女通信」にのみ出現する単語であり、2行目は「スポーツウォッチ」にだけ出現する単語である。頻出していたストップワードっぽい単語はきれいに消えていることがわかる。

Set(今風, 味の素, 呼び名, 愛車, ヨネスケ, 週末, 空き, 華子, 姓名, 時折, 越える, サン, 思い当たる, はしご, ロードショ, 新鮮味, 調べる, 札, 執筆, 麻美, 養子, 駅, ミッション, フミ, 初恋, 鉄則, 落とし穴, さゆり, メモリ, 飲み食い, 和子, 避妊, 苦痛, アカシックレコードリーディング, ラッキ, 本体, 真美子, よそ見, マザー, 尚更, だれ, 盛, sweet, 余震, 心得, アドレス, 器用貧乏, 渋谷, 次男, 法的, 知人, 集まり, ミニサイズ, 皆無, へえ, 眺める, 洋子, 膨大, あっぱれ, 数少ない, ハッピ, 手数料, ローラ, 安価, 波風, 甲斐, 統計, 労働省, 主演, ntt, 以下省略)
Set(緊迫, かしぐ, ほとぼり, 在米, フジ, 見れる, フェンシング, 連夜, 被, 205, 兼備, 2014, 藤田, 長島, 曙, 颯爽, プロレスラ, セーフコ, 説く, はしる, 知良, アスリートファン, 鳥肌, 主審, 沸く, 周知, ちょう, 円熟, オールナイト, 卓, あしらい, 不用意, 栗山, 火蓋, やらす, 弘和, 修一, 一角, 平泳ぎ, 98, ゴールデンゴールズ, 演説, 敗, 今井, アリエン, スプリングス, 戦後, beautiful, しょうもない, 113, 敗者, 野, 仰天, 素性, 聖, sunday, 井端, イーグルススカウト, 批評, スルーパス, 前線, 弁解, ユース, クロー, 人情, 用水, やぎ, cb, クーラ, 興行, 選考, mmaplanet, きまる, 哲也, 織る, ラピュタ, グルノーブル, ロマン, クロアチア, brad, 山里, wbc, 権限, pm, ぶっつける, 抜擢, いづみ, アフリカ, 以下省略)

これをもってそれぞれの分野の専門用語であると言い切るには難があるが、どちらかが「独女通信」でどちらかが「スポーツウォッチ」だという2択の問題を出されたならば、ほとんどの人が正解するくらいには専門用語っぽい出力が得られているといえるのではないだろうか。

| 関口宏司 | NLP | 09:00 | comments(1) | trackbacks(0) |
word2vec for Lucene ご紹介

Luceneインデックスをコーパスとみなして動作する word2vec for Lucene を開発したのでその使い方を紹介しよう。word2vec は Tomas Mikolov らによって提案/開発された単語をベクトルに変換するOSSツールである。オリジナルの word2vec は自然言語で書かれたテキストファイルを読み込み、単語ベクトルを出力するようになっている。

word2vec for Lucene はテキストファイルの代わりにLuceneインデックスを入力コーパスとして用いる。オリジナルの word2vec が扱うテキストファイルは単語単位で分かち書きされている必要がある。この点は英語テキストなどでは問題ないが、単語で分かち書きされていない日本語などではあらかじめMeCabなどの形態素解析器や分かち書きツールを用いて単語で分かち書きされたテキストファイルを用意しておかなければならない。また英語であっても大文字→小文字変換や単語テキストの直後に続くピリオド/カンマの削除など、事前の正規化作業が必要になってくる。word2vec for Lucene では Luceneインデックスを入力コーパスとして用いるため、事前の正規化作業が不要である。

以下では簡単に試していただけるよう、word2vec for Lucene のデモを実行する手順を説明する。大まかな手順は:

1.word2vec for Lucene のダウンロード
2.デモデータの準備
3.Lucene/Solrインデックスの準備(デモデータの登録)
4.単語ベクトルの作成
5.単語ベクトルで遊ぶ

という感じである。すでにLuceneインデックスを持っている方は手順2〜3の代わりに手持ちのLuceneインデックスを手順4で指定することにしてもよい。word2vec for LuceneはLucene 4.10.2ベースで作成したが、(試していないが)たいていのLucene 4.x インデックスで動作するものと思われる。したがって、Solr 4.x はもちろんのこと、Elasticsearch(バージョンはよく知らないが1.x系以降)で作成したインデックスも指定できる。

手順5で楽しい結果を得るためにはそれなりに大きなコーパスが必要である。数百万文書など大きなLuceneインデックスを持っている方はぜひ word2vec for Lucene を試していただきたい。

以下手順を示すが、簡単のために /Users/koji/work ディレクトリ以下に Solr 環境と word2vec for Lucene 環境をインストールする想定で話を進める。

手順1.word2vec for Lucene のダウンロード
$ pwd
/Users/koji/work
$ git clone https://github.com/kojisekig/word2vec-lucene.git
手順2.デモデータの準備
$ pwd
/Users/koji/work
$ cd word2vec-lucene
# オリジナルの word2vec でも使用されている英語コーパス text8 をダウンロードして Solr 形式に変換
$ ant t8-solr
$ ls -l text8*
-rw-r--r--  1 koji  staff  100000000  6  9  2006 text8
-rw-r--r--  1 koji  staff  100017005 12  3 13:44 text8.txt
-rw-r--r--  1 koji  staff  100017078 12  3 13:44 text8.xml
-rw-r--r--  1 koji  staff   31344016 12  3 13:40 text8.zip
手順3.Lucene/Solrインデックスの準備(デモデータの登録)

コンソールを2つ用意して最初のコンソールでSolrを起動する。

$ pwd
/Users/koji/work

# Solrのダウンロード
$ wget http://ftp.meisei-u.ac.jp/mirror/apache/dist/lucene/solr/4.10.2/solr-4.10.2.tgz
$ tar xvzf solr-4.10.2.tgz

# Solrの起動
$ cd solr-4.10.2/example
$ java -Dsolr.solr.home=/Users/koji/work/word2vec-lucene/solrhome -Dsolr.dir=/Users/koji/word/solr-4.10.2 -jar start.jar

2つめのコンソールではtext8コーパスをSolrに登録する。

$ pwd
/Users/koji/work
$ cd word2vec-lucene
# Solr形式に変換した英語コーパスをSolrに登録
$ ./post.sh collection1 text8.xml
手順4.単語ベクトルの作成

demo-word2vec.sh スクリプトにSolrコア名を指定してword2vecを実行する。実行結果はvectors.txtというファイルに出力される。

$ pwd
/Users/koji/work
$ cd word2vec-lucene
$ ./demo-word2vec.sh collection1
$ ls -l vectors.txt 
-rw-r--r--  1 koji  staff  136053041 12  3 15:31 vectors.txt
手順5.単語ベクトルで遊ぶ

demo-distance.sh を実行するとvectors.txtファイルを読み込んで入力待ちになる。そこで単語を入力すると、その単語に最も近い(コサインを計算)ベクトルを持つ単語上位40個を表示する。

$ ./demo-distance.sh
cat
Word: cat
Position in vocabulary: 2601

                                              Word      Cosine distance
------------------------------------------------------------------------
                                              cats		0.511078
                                               dog		0.471308
                                              dogs		0.469539
                                        sighthound		0.452233
                                           bobtail		0.436424
                                             tapir		0.424105

demo-analogy.sh を実行するとvectors.txtファイルを読み込んで入力待ちになるので、3つの単語をスペース区切りで入力する。以下ではman king womanと入力しているが、「manに対するkingの関係を、womanに適用するとどうなるか」という意味である。するとqueenが期待値になるが、実行結果もそのようになる。

$ ./demo-analogy.sh
man king woman
日本語で試す場合

以上の手順はオリジナルの word2vec でも使用している text8 という英語の正規化済みのコーパスを使った手順であるが、以下では日本語の(正規化済みでない)コーパスを使った手順も紹介しよう。デモデータは livedoor ニュースコーパスを用いる。ロンウイットのサイトから Solr ネイティブ形式に加工した livedoor ニュースコーパスをダウンロードする。

$ pwd
/Users/koji/work
$ cd word2vec-lucene
$ mkdir work
$ cd work
$ pwd
/Users/koji/work/word2vec-lucene/work
$ wget http://www.rondhuit.com/download/livedoor-news-data.tar.gz
$ tar xvzf livedoor-news-data.tar.gz
$ cd ..

ダウンロードした livedoorニュースコーパスをSolrに登録し、word2vecを実行する。コア名にはldccを指定する。また、-aオプションでLuceneのAnalyzerクラスを指定する。また以下では-fオプションで出力先ベクトルファイル名を指定している(指定しないとデフォルトのvectors.txtとなってしまい、先ほど作成した英語の単語ベクトルファイルを上書きしてしまう)。

$ ./post.sh ldcc work/*.xml
$ ./demo-word2vec.sh ldcc -a org.apache.lucene.analysis.ja.JapaneseAnalyzer -f vectors-ldcc.txt
$ ./demo-distance.sh -f vectors-ldcc.txt
結婚
野球
デモデータ以外のLuceneインデックスで試す場合の注意点

word2vec for Lucene で配布しているデモ実行スクリプト demo-word2vec.sh を見てもらうとわかるように、いくつかのパラメータがハードコーディングで指定されている。以下はLuceneに関連するパラメータである。これを手持ちのLuceneインデックスに合うように適宜指定しなおせばLucene 4.x インデックスのデータでword2vecが動くはずである。

オプション説明
-indexLuceneインデックスのディレクトリを指定する。
-fieldword2vec を実行するLuceneインデックスのフィールド名を指定する。このフィールドはindexedでかつstoredでなければならない。
-analyzer-fieldオプションで指定されたフィールドのstoredデータをここで指定されたLuceneのAnalyzerクラスでanalyzeする。

-analyzer オプションについては、storedデータではなくTermVectorでもよかったのだが、TermVectorを保存しているLuceneインデックスは少なく、処理速度的にも疑問だったため、storedデータをここで指定するLuceneのAnalyzerクラスでanalyze する方針をとった。ではなぜindexedでなければいけないかというと、(オリジナル実装でも)word2vecではコーパスを2度読んでいて、1回目の読み込みで単語表を作成しているが、indexedであればそこは一瞬で完了し、なんといってもLuceneっぽいからである。また、word2vecで解析したくなるようなLuceneフィールドはたいていindexedでかつstoredと考えられるので、多くのLuceneインデックスオーナーにはこの条件は受け入れられるはずである。

相当数の文書が入っているLuceneインデックスを持っている方は、デモデータで動作を確認したあと、ぜひword2vec for Luceneを手持ちのLuceneインデックス上で試していただき、どんな結果になったか教えていただければありがたい。

| 関口宏司 | NLP | 09:00 | comments(0) | trackbacks(0) |
+ Solrによるブログ内検索
+ PROFILE
 123456
78910111213
14151617181920
21222324252627
28293031   
<< December 2014 >>
+ 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