ラベル Solr の投稿を表示しています。 すべての投稿を表示
ラベル Solr の投稿を表示しています。 すべての投稿を表示

金曜日, 9月 10, 2010

Solrクエリのパーサ2

以下を忘れいたので、GINによるSolrクエリパーサを改訂しました。

・NOT
・レンジクエリ(pub_date:[2009-10-01T00:00:00Z+TO+*])

// Solrクエリパーサの作成(LL) v0.2

// パーサジェネレータを読込み
load('work\\mod_gin.js');

// パーサを作成(EBNFで文法を定義)
// JS_STRINGはダブルクウォートで括らなくてはならないのでTermを定義して使う
// Termで+記号は定義せず+desc/+ascを別書きとする(+OR+等とかぶるため全体がターム扱いとなる)
// Rangeには[]で括って作られるレンジクエリ用の記述を入れて別出し
var calc = new Gin.Grammar({
Solr: / Object ( '&' Object )* /,
Object: / ( Value '=' Factor ) /,
Factor: / Value ( ',' Factor | '+AND+' Factor | '+OR+' Factor | '+NOT+' Factor )* /,
Value: / Term | '(' Factor ')' /,
Term: / <[a-zA-Z0-9_.]+> ':[' Range ']' | <[a-zA-Z0-9_.:]+(\+desc|\+asc)?> /,
Range: / <[a-zA-Z0-9_.+*\-]+> /
}, "Solr", Gin.SPACE);

// 検証するSolrクエリ
var strInput = 'start=0&q=AREA_CD:050+OR+DISP:1+AND+HAN_CD:011)+AND+EKI_CD:26610+AND+pub_date:[2009-10-01T00:00:00Z+TO+*]&sort=EKI_CD+asc,HAN_CD+desc&wt=javabin&rows=0&version=2.2';

// パーサのデバッグを行うときは以下のコメントを復活
var input = [
// 'q=((AAA:1+AND+BBB:2))&start=1',
// '"q"=(("AAA:x"+AND+"BBB:2")+AND+"CCC:3")&"start"=1&"var"=1.1',
// '"q"=("DDD"+OR+("AAA"+AND+"BBB")+AND+"CCC")&"sort"="test+desc","kkk+asc"&"start"=1',
strInput
];

// 検証!
for (var i = 0; i < input.length; i++) {
var match = calc.parse(input[i]);
if (match && match.full){
print("AST: " + match.value.toSource());
}else{
print(input[i]);
print("Sentence was wrong.");
}
}

月曜日, 8月 09, 2010

Solrクエリのパーサ1

"Days on the Moon"さんのブログを参考に、Solrのクエリを整形(Lint)する目的でパーサを作る実験中です。

以下、なんとなく通った版です(GINはmod_gin.jsとリネームし、rhinoで起動)。

// Solrクエリパーサの作成(LL) v0.1

// パーサジェネレータを読込み
load('work\\mod_gin.js');

// パーサを作成(EBNFで文法を定義)
// JS_STRINGはダブルクウォートで括らなくてはならないのでTermを定義して使う
// Termで+記号は定義せず+desc/+ascを別書きとする(+OR+等とかぶるため全体がターム扱いとなる)
// Termには数字は入ってこない想定(Valueに$REALがあるため)
var calc = new Gin.Grammar({
Solr: / Object ( '&' Object )* /,
Object: / ( Value '=' Factor ) /,
Factor: / Value ( ',' Factor | '+AND+' Factor | '+OR+' Factor )* /,
Value: / $REAL | Term | '(' Factor ')' /,
Term: / <[a-zA-Z0-9:_.]+(\+desc|\+asc)?> /
}, "Solr", Gin.SPACE);

// 検証するSolrクエリ
var strInput = 'start=0&q=(AREA_CD:050+OR+DISP:1+AND+HAN_CD:011)+AND+EKI_CD:26610&sort=EKI_CD+asc,HAN_CD+desc&wt=javabin&rows=0&version=2.2';

// パーサのデバッグを行うときは以下のコメントを復活
var input = [
// 'q=((AAA:1+AND+BBB:2))&start=1',
strInput
];

// 検証!
for (var i = 0; i < input.length; i++) {
var match = calc.parse(input[i]);
if (match && match.full){
print("AST: " + match.value.toSource());
}else{
print(input[i]);
print("Sentence was wrong.");
}
}

日曜日, 10月 25, 2009

[Solr] tikaを簡単に

curlを2回つなげると、簡単にウェブページを検索対象にできる。

konpyuta:~/work tf0054$ curl -s http://lucene.apache.org/tika/ | curl 'http://localhost:8983/solr/update/extract?literal.id=doc5&literal.url=doc5&commit=true' -F "myfile=@-"
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">76</int></lst>
</response>
konpyuta:~/work tf0054$ 

ちなみに、curlの"-F"オプションで指定ファイルをPOSTすることができる(ココでは前のcurlから受け取ったSTDINを流すために"-"で受けている)。

木曜日, 9月 10, 2009

[Solr] GoSenをまた修正!

Luceneが2.9-rc2になったからか、またSolrでgosenが動かなくなっていたので修正しました。
lucene-ja-gosen-1.0.2.zipとして置いておきます。

日曜日, 6月 14, 2009

[Solr] GoSenを修正!

たぶん、全文検索ライブラリluceneに入った修正(LUCENE-1636)のために、先のgosenセットがtrunkのSolrが起動すら出来なくなっていました(IllegalAccessExceptionがPosFilter初期化時に発生!)。今日までupdateしてなかったので気が付かず。

で、読めないJavaをなんとなく眺め、結局、本体の似たようなFilterのソースと同じ初期方法にかえる(superを呼ぶだけにする)ことで解消できている様子。なので、新lucene-ja-gosenセットとして置いておきます。

よかったー。と直したのはいいけど、結局(Solrの)v1.4はいつ出るんだろう。。。

日曜日, 5月 24, 2009

[Solr] WebService::Solrが

自前でSolrのレスポンスを、XML::Simple使って解析しようとして四苦八苦していたところ、、ふと思いついて調べてみたら、案の定WebService::Solrなるものが。。

早速書き直してみたところ、SolrのレスポンスのクセxXML::Simpleのクセにやられていた(例外処理ばかりだったコード)が、シンプルにんありました。

最初から調べておけば。。。

追伸:
XMLじゃなくJSONのレスポンスを解析してますね、、なるほどー。そういえば、確かにJSON用CPANモジュールをいっぱいダウンロードしていました(StrawberryPerlさいこうです)。

追伸:
英語の解説ページを発見。

土曜日, 4月 18, 2009

[Solr] GoSenを使う

Javaで形態素解析ライブラリはもうSenしかない状況、、だと思っていましたが、(ちょっと途中で投げ出されている感はあるものの)GoSenのほうが辞書作成もJavaだけでできる等、整備されていて良さそうです。
ただ、Senはトークナイザだけを提供しているので、Solrで使うにはLucene-jaというのを別途取ってきて、そこに入っている"アナライザ"経由で使わなくてはなりません。
つまり、(Lucene-jaの)アナライザが使うトークナイザを、SenからGoSenに変えればよい。。のですが、GoSenはSenから多少構成が変わっているため「ただjarを入れ替え」るだけでは動きません。

細かくはまた別に書こうと思いますが、hideakiさんのブログを参考に、
・Lucene-ja(のSenTokenizer.javaを)書き換え
・無いと不便なbuild.xmlを作成
としたlucene-ja-gosenセットを作りましたので、上げておきます(JDK6で作ったので5で使うならlib以下にあるgosen.jarとか作り直しかも)。

ちなみに、GoSenでもsen.xmlは必要ですが(厳密にはこれはLucene-ja側で使うファイルなので当たり前)、testdata/dictionary/dictionary.xmlをコピーして使えばOKです。

簡単に使い方を。

1.Lucene-ja-gosenをダウンロードして解凍(DIR-Aとする)
2.中のGoSen.tgzをさらに解凍(DIR-Bとする)
4.DIR-B/testdata/dictionaryへ移動してant(辞書作成)
3.sen/confとディレクトリを掘る
5.そのディレクトリへdictionaryで出来たファイルをコピー
 cp *.sen sen/conf
6.そのディレクトリへ以下リネームしてコピー
 mv dictionary.xml sen/conf/sen.xml
7.動かしたいSolrのWEB-INF/libへ移動して以下コピー(※追加参照)
 cp DIR-A/lucene-ja-gosen*.jar (Solrの)WEB-INF/lib
 cp DIR-B/lib/gosen*.jar (Solrの)WEB-INF/lib
8.ココを参考にSolrのschema.xmlへ組込み(senの場合と全く同じで)

/sen/confは起動時の"-Dsen.home"指定を使いたくないからココにしているだけなので変更は可能です。が、辞書とsen.xmlは同じ場所に置きましょう。

追加:
 手順の7は、Solr自体がbuildできる状態なら、build.xmlと同じディレクトリにあるlib以下にこれらjarを入れておけば、適当に(WEB-INF/libに)はいるようなwarを作ってくれます。

木曜日, 4月 16, 2009

[Solr] Nutchでサイトクロール

Solrを使ってサイトクロールを行う方法が、公開されていたので、

やってみた。

Nutchはウェブスパイダーとしてのクロール機能を提供している。内部に分散ファイルシステムたるHadoopを持っていのだが、今回はこれは使わない方法(のようだ)。

- - - -

1. Nutchを<a href="http://hudson.zones.apache.org/hudson/job/Nutch-trunk/">ダウンロード</a>し、解凍する。

 tar xzf apache-nutch-1.0.tar.gz

2. Solrの設定を行う

Nutchの中にはschema.xmlなどSolrを連携して使うためのサンプルの設定ファイルが含まれています。

a. schema.xmlの配置
apache-nutch-1.0/conf to directory apache-solr-1.3.0/example/solr/conf

b. “content”フィールドの設定変更

<field name=”content” type=”text” stored=”true” indexed=”true”/>

c. クローラ用リクエストハンドラの作成

以下をsolrconfig.xmlに追記します。

<requestHandler name="/nutch" class="solr.SearchHandler" >
<lst name="defaults">
<str name="defType">dismax</str>
<str name="echoParams">explicit</str>
<float name="tie">0.01</float>
<str name="qf">
content^0.5 anchor^1.0 title^1.2
</str>
<str name="pf">
content^0.5 anchor^1.5 title^1.2 site^1.5
</str>
<str name="fl">
url
</str>
<str name="mm">
2&lt;-1 5&lt;-2 6&lt;90%
</str>
<int name="ps">100</int>
<bool hl="true"/>
<str name="q.alt">*:*</str>
<str name="hl.fl">title url content</str>
<str name="f.title.hl.fragsize">0</str>
<str name="f.title.hl.alternateField">title</str>
<str name="f.url.hl.fragsize">0</str>
<str name="f.url.hl.alternateField">url</str>
<str name="f.content.hl.fragmenter">regex</str>
</lst>
</requestHandler>

3. Solrを起動しておきます。

cd apache-solr-1.3.0/example
java -jar start.jar

4. Nutchの設定を行います。

a. apache-nutch-1.0/confにあるnutch-site.xmlの中身を以下のものにまるっと入れ替えます。
ここでは、クローラの名前や、有効化するプラグイン、ドメイン単位でみたときの最大同時接続数などを指定します。

<?xml version="1.0"?>
<configuration>
<property>
<name>http.agent.name</name>
<value>nutch-solr-integration</value>
</property>
<property>
<name>generate.max.per.host</name>
<value>100</value>
</property>
<property>
<name>plugin.includes</name>
<value>protocol-http|urlfilter-regex|parse-html|index-(basic|anchor)|query-(basic|site|url)|response-(json|xml)|summary-basic|scoring-opic|urlnormalizer-(pass|regex|basic)</value>
</property>
</configuration>

b. apache-nutch-1.0/confにあるregex-urlfilter.txtの中身を書き換えます。

-^(https|telnet|file|ftp|mailto):
 
# skip some suffixes
-\.(swf|SWF|doc|DOC|mp3|MP3|WMV|wmv|txt|TXT|rtf|RTF|avi|AVI|m3u|M3U|flv|FLV|WAV|wav|mp4|MP4|avi|AVI|rss|RSS|xml|XML|pdf|PDF|js|JS|gif|GIF|jpg|JPG|png|PNG|ico|ICO|css|sit|eps|wmf|zip|ppt|mpg|xls|gz|rpm|tgz|mov|MOV|exe|jpeg|JPEG|bmp|BMP)$
 
# skip URLs containing certain characters as probable queries, etc.
-[?*!@=]
 
# allow urls in foofactory.fi domain
+^http://([a-z0-9\-A-Z]*\.)*lucidimagination.com/
 
# deny anything else
-.

5. 初期URLリスト(クロール起点)ファイルを作成します。

mkdir urls
echo "http://www.lucidimagination.com/" > urls/seed.txt

6. 初期URLのページをクロールしてNutchのcrawldbに格納します。

bin/nutch inject crawl/crawldb urls

konpyuta:~/work/nutch tf0054$  bin/nutch inject crawl/crawldb urls
Injector: starting
Injector: crawlDb: crawl/crawldb
Injector: urlDir: urls
Injector: Converting injected urls to crawl db entries.
Injector: Merging injected urls into crawl db.
Injector: done
konpyuta:~/work/nutch tf0054$

7. 取得したページを解析してコンテンツを抜き出します。

bin/nutch generate crawl/crawldb crawl/segments

konpyuta:~/work/nutch tf0054$ bin/nutch generate crawl/crawldb crawl/segments
Generator: Selecting best-scoring urls due for fetch.
Generator: starting
Generator: segment: crawl/segments/20090416032246
Generator: filtering: true
Generator: jobtracker is 'local', generating exactly one partition.
Generator: Partitioning selected urls by host, for politeness.
Generator: done.
konpyuta:~/work/nutch tf0054$

上のコマンドで、crawl/segments以下に新たなクロール対象のディレクトリを作成します。 that at this point contains files that store the url(s) to be fetched. In the following commands we need the latest segment dir as parameter so we’ll store it in an environment variable:

export SEGMENT=crawl/segments/`ls -tr crawl/segments|tail -1`

クロールを開始します。

bin/nutch fetch $SEGMENT -noParsing

konpyuta:~/work/nutch tf0054$ bin/nutch fetch $SEGMENT -noParsing
Fetcher: Your 'http.agent.name' value should be listed first in 'http.robots.agents' property.
Fetcher: starting
Fetcher: segment: crawl/segments/20090416032246
Fetcher: threads: 10
QueueFeeder finished: total 1 records.
fetching http://www.lucidimagination.com/
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-activeThreads=1, spinWaiting=0, fetchQueues.totalSize=0
-activeThreads=1, spinWaiting=0, fetchQueues.totalSize=0
-finishing thread FetcherThread, activeThreads=0
-activeThreads=0, spinWaiting=0, fetchQueues.totalSize=0
-activeThreads=0
Fetcher: done
konpyuta:~/work/nutch tf0054$

コンテンツをパースします。

bin/nutch parse $SEGMENT

konpyuta:~/work/nutch tf0054$ bin/nutch parse $SEGMENT
konpyuta:~/work/nutch tf0054$

Then I update the Nutch crawldb.
updatedb コマンドを使うと、先にとってきたページのパースと、もうパースされて見つかっているURLページの取得をパイプライン的に並行して行わせることができます。なお、Nutchは取得した各ページの状態を覚えているため、同じページを何度も取得しに行ってしまうことはありません。

bin/nutch updatedb crawl/crawldb $SEGMENT -filter -normalize

konpyuta:~/work/nutch tf0054$ bin/nutch updatedb crawl/crawldb $SEGMENT -f
ilter -normalize
CrawlDb update: starting
CrawlDb update: db: crawl/crawldb
CrawlDb update: segments: [crawl/segments/20090416032246]
CrawlDb update: additions allowed: true
CrawlDb update: URL normalizing: true
CrawlDb update: URL filtering: true
CrawlDb update: Merging segment data into db.
CrawlDb update: done
konpyuta:~/work/nutch tf0054$

これまでが、クロールの1サイクルとなります。

8. linkdbを作る

bin/nutch invertlinks crawl/linkdb -dir crawl/segments

konpyuta:~/work/nutch tf0054$ bin/nutch invertlinks crawl/linkdb -dir crawl/segments

LinkDb: starting
LinkDb: linkdb: crawl/linkdb
LinkDb: URL normalize: true
LinkDb: URL filter: true
LinkDb: adding segment: file:/Users/tf0054/work/nutch-2009-04-15_04-01-57/crawl/segments/20090416032246
LinkDb: done
konpyuta:~/work/nutch tf0054$

9. 全セグメントからSolrにコンテンツを送る

bin/nutch solrindex http://127.0.0.1:8983/solr/ crawl/crawldb crawl/linkdb crawl/segments/*

10. Solrにて検索可能となったか確認する。

http://127.0.0.1:8983/solr/nutch/?q=solr&amp;version=2.2&amp;start=0&amp;rows=10&amp;indent=on&amp;wt=json

- - - - -

木曜日, 2月 19, 2009

[Java] Senのバグ

Javaで形態素解析をするときに、使われるSenだが本家からダウンロードできるオリジナルソースはバグ付き。これはgnarlさんのページに修正方法が詳しく記載されている様子。

金曜日, 12月 19, 2008

[Solr] SpellCheckComponent

Solrには「もしかして検索」を実装するのに使えそうなSpellCheckComponentというコンポーネントがあるが、日本語は何故か使えない様子(出所はIBMの開発者向けページ/いつも質が高く関心する)。
Lukeで見るところ、SpellCheck用フィールドのトークナイザをMeCabにしているから、当然キチンとword及びstart3なんかにも、想定した切り方で入っているようだが。。
問題はクエリ側か?

参考:LingPipe, Wiki

水曜日, 11月 26, 2008

[Solr] jQueryのSolrプラグイン

すばらしい!