Solr には Tagger Handler というテキストへのタグ付けの機能があります。
タグ付けはかなり幅の広い技術で、高度な自然言語処理を用いてアノテーションを与える手法もある一方で、辞書として与えられた単語を単純に抽出する手法もあります。Solr の Tagger Handler は後者です。
Tagger Handler ではSolrのインデックスを辞書として使い、Tagger Handler へ送られたテキスト内に含まれる辞書の単語をタグ付けして出力します。与えられたキーワードがインデックスされたドキュメントに含まれるかどうかを調べる検索処理と対照的ですが、要素の技術は共通しています。
Solr リファレンスには Tagger Handler のチュートリアルが含まれているので、それに沿って動作を確認してみます。
まず geonames というコレクションを作ります。
bin/solr create -c geonames
スキーマを API で定義します。
curl -X POST -H 'Content-type:application/json' http://localhost:8983/solr/geonames/schema -d '{
"add-field-type":{
"name":"tag",
"class":"solr.TextField",
"postingsFormat":"FST50",
"omitNorms":true,
"omitTermFreqAndPositions":true,
"indexAnalyzer":{
"tokenizer":{
"class":"solr.StandardTokenizerFactory" },
"filters":[
{"class":"solr.EnglishPossessiveFilterFactory"},
{"class":"solr.ASCIIFoldingFilterFactory"},
{"class":"solr.LowerCaseFilterFactory"},
{"class":"solr.ConcatenateGraphFilterFactory", "preservePositionIncrements":false }
]},
"queryAnalyzer":{
"tokenizer":{
"class":"solr.StandardTokenizerFactory" },
"filters":[
{"class":"solr.EnglishPossessiveFilterFactory"},
{"class":"solr.ASCIIFoldingFilterFactory"},
{"class":"solr.LowerCaseFilterFactory"}
]}
},
"add-field":{"name":"name", "type":"text_general"},
"add-field":{"name":"name_tag", "type":"tag", "stored":false },
"add-copy-field":{"source":"name", "dest":["name_tag"]}
}'
Tagger Handler を API で設定します。
curl -X POST -H 'Content-type:application/json' http://localhost:8983/solr/geonames/config -d '{
"add-requesthandler" : {
"name": "/tag",
"class":"solr.TaggerRequestHandler",
"defaults":{"field":"name_tag"}
}
}'
http://download.geonames.org/export/dump/cities1000.zip
からサンプルデータをダウンロードし、/tmp に展開しておきます。
サンプルデータを geonames コレクションに投入します。
bin/post -c geonames -type text/csv \
-params 'optimize=true&maxSegments=1&separator=%09&encapsulator=%00&fieldnames=id,name,,alternative_names,latitude,longitude,,,countrycode,,,,,,population,elevation,,timezone,lastupdate' \
/tmp/cities1000.txt
タグ付けの動作を確認します。
$ curl -X POST \
'http://localhost:8983/solr/geonames/tag?overlaps=NO_SUB&tagsLimit=5000&fl=id,name,countrycode&wt=json&indent=on' \
-H 'Content-Type:text/plain' -d 'Hello New York City'
{
"responseHeader":{
"status":0,
"QTime":1},
"tagsCount":1,
"tags":[{
"startOffset":6,
"endOffset":19,
"ids":["5128581"]}],
"response":{"numFound":1,"start":0,"docs":[
{
"id":"5128581",
"name":["New York City"],
"countrycode":["US"]}]
}}
リファレンスによると、Tagger Handler へのリクエストではインデックスのどのフィールドを辞書として扱うかを示す filed パラメータが必須となっていますが、このリクエストには field パラメータが含まれていません。その代わりに Tagger Handler の設定で以下を指定しているため、デフォルトで name_tag フィールドが使われます。
"defaults":{"field":"name_tag"}
を指定しているため、デフォルトで name_tag フィールドが使われます。
複数のエンティティが含まれる場合も試してみました。
$ curl -X POST 'http://localhost:8983/solr/geonames/tag?overlaps=NO_SUB&tagsLimit=5000&fl=id,name,countrycode&wt=json&indent=on' -H 'Content-Type:text/plain' -d 'Hello New York City. Hello Los Angeles.'
{
"responseHeader":{
"status":0,
"QTime":0},
"tagsCount":2,
"tags":[{
"startOffset":6,
"endOffset":19,
"ids":["5128581"]},
{
"startOffset":27,
"endOffset":38,
"ids":["3882428",
"3801497",
"3998147",
"3998148",
"8858843",
"3705542",
"3705544",
"1705545",
"5368361"]}],
"response":{"numFound":10,"start":0,"numFoundExact":true,"docs":[
{
"id":"3882428",
"name":["Los Ángeles"],
"countrycode":["CL"]},
{
"id":"3801497",
"name":["Los Ángeles"],
"countrycode":["MX"]},
{
"id":"3998147",
"name":["Los Angeles"],
"countrycode":["MX"]},
{
"id":"3998148",
"name":["Los Angeles"],
"countrycode":["MX"]},
{
"id":"8858843",
"name":["Los Ángeles"],
"countrycode":["MX"]},
{
"id":"3705542",
"name":["Los Ángeles"],
"countrycode":["PA"]},
{
"id":"3705544",
"name":["Los Ángeles"],
"countrycode":["PA"]},
{
"id":"1705545",
"name":["Los Angeles"],
"countrycode":["PH"]},
{
"id":"5128581",
"name":["New York City"],
"countrycode":["US"]},
{
"id":"5368361",
"name":["Los Angeles"],
"countrycode":["US"]}]
}}
“New York City” と “Los Angeles” の両方がヒットしました。様々な国の “Los Angeles” がタグとして出力されています。
Tagger Handler へのリクエストにはフィルタクエリを含めることができます。
$ curl -X POST 'http://localhost:8983/solr/geonames/tag?overlaps=NO_SUB&tagsLimit=5000&fl=id,name,countrycode&wt=json&indent=on&fq=countrycode:US' -H 'Content-Type:text/plain' -d 'Hello New York City. Hello Los Angeles.'
{
"responseHeader":{
"status":0,
"QTime":0},
"tagsCount":2,
"tags":[{
"startOffset":6,
"endOffset":19,
"ids":["5128581"]},
{
"startOffset":27,
"endOffset":38,
"ids":["5368361"]}],
"response":{"numFound":2,"start":0,"numFoundExact":true,"docs":[
{
"id":"5128581",
"name":["New York City"],
"countrycode":["US"]},
{
"id":"5368361",
"name":["Los Angeles"],
"countrycode":["US"]}]
}}
先程のリクエストに fq=contrycode:US を追加することで、結果を US に限定できました。