ご利用にはKandaSearchへの
ユーザー登録(無料)が必要です
最新バージョン: 1.0.0
開発者: RONDHUIT
ダウンロード数: 39
最終更新日: 2022-05-30
Copyright: RONDHUIT Co.,LTD
最新バージョン: 1.0.0
開発者: RONDHUIT
ダウンロード数: 39
最終更新日: 2022-05-30
Copyright: RONDHUIT Co.,LTD
Apache Solr ハンズオンセミナー「第4回 全文検索のさまざまなテクニック」のスライドです。
第4回 全文検索のさまざまなテクニック Apache Solr ハンズオンセミナー
株式会社ロンウイット
関口宏司 @kojisays
2022年5月30日 | 初版 |
---|---|
これから Apache Solr のいろいろな機能を使っていきます。本セミナーでは Apache Solr 環境を簡単に準備できる KandaSearch を通じて Apache Solr を使っていきます。
そのためには、 https://kandasearch.com/ にログイン後、プロジェクトを作成します。
(お試しになりたい方のみお試しください。このステップを飛ばしても以降の[演習]には差し支えございません)
作成したプロジェクト内に検索エンジンインスタンス、つまり Apache Solr を作成してみましょう。
具体例として、titleとbodyフィールドを与えられたkeywordで検索する場面を考えます。以下の3つのやり方があります。
<field name="text" type="text_ja" indexed="true" stored="false" multiValued="true"/>
<copyField source="title" dest="text"/>
<copyField source="body" dest="text"/>
df=text&q=keyword
q.op=OR
q=title:keyword body:keyword
defType=edismax
qf=title^3 body
q=keyword
下のように2件の文書を持つインデックスに対して、
apple computer
をtitleとbodyフィールドを横断検索する場合を考えます。
インデックスの内容(カッコ内数値はフィールドの重みを示す) | id | title (x1.5) | body (x1.0) | |-------|--------------|---------------| | item1 | apple | apple fruit | | item2 | computer | apple desktop |
BQのOR演算子で展開する方法
q.op=OR&
q=(title:apple^1.5 body:apple) (title:computer^1.5 body:computer)
BQ { BQ( title:apple^1.5 OR body:apple ) OR
BQ( title:computer^1.5 OR body:computer ) }
⇒ BQ( A OR B ) ⇒ スコアはA+Bの合計となる。
id | title (x1.5) | body (x1.0) | |
---|---|---|---|
item1 | apple | apple fruit | (1.5 + 1.0) + (0.0 + 0.0) = 2.5 |
item2 | computer | apple desktop | (0.0 + 1.0) + (1.5 + 0.0) = 2.5 |
BQとDMQの組み合わせで展開する方法
defType=edismax&qf=title^1.5 body&
q=apple computer
BQ { DMQ( title:apple^1.5 | body:apple ) OR
DMQ( title:computer^1.5 | body:computer ) }
⇒ DMQ( A | B ) ⇒ スコアは max(A,B) となる。
id | title (x1.5) | body (x1.0) | |
---|---|---|---|
item1 | apple | apple fruit | max(1.5, 1.0) + max(0.0, 0.0) = 1.5 |
item2 | computer | apple desktop | max(0.0, 1.0) + max(1.5, 0.0) = 2.5 |
下のように3件の文書を持つインデックスに対して、
apple computer
をtitleとbodyフィールドを横断検索する場合を考えます。
id | title (x1.5) | body (x1.0) |
---|---|---|
item1 | apple | apple fruit |
item2 | computer | apple desktop |
item3 | computer | apple computer |
edismaxをtieパラメーターなしで使った場合
defType=edismax&qf=title^1.5 body&
q=apple computer
BQ { DMQ( title:apple^1.5 | body:apple ) OR
DMQ( title:computer^1.5 | body:computer ) }
id | title (x1.5) | body (x1.0) | |
---|---|---|---|
item1 | apple | apple fruit | max(1.5, 1.0) + max(0.0, 0.0) = 1.5 |
item2 | computer | apple desktop | max(0.0, 1.0) + max(1.5, 0.0) = 2.5 |
item3 | computer | apple computer | max(0.0, 1.0) + max(1.5, 1.0) = 2.5 |
BQとDMQの組み合わせで展開する方法
defType=edismax&qf=title^1.5 body&tie=0.1&
q=apple computer
BQ { DMQ( title:apple^1.5 | body:apple ) w/ tie=0.1 OR
DMQ( title:computer^1.5 | body:computer ) w/ tie=0.1 }
⇒ DMQ( A | B ) w/ tie=0.1 ⇒ スコアは max(A,B) + second(A,B)*0.1 となる。
id | title (x1.5) | body (x1.0) | |
---|---|---|---|
item1 | apple | apple fruit | max(1.5, 1.0) + 1.00.1 + max(0.0, 0.0) + 0.00.1 = 1.6 |
item2 | computer | apple desktop | max(0.0, 1.0) + 0.00.1 + max(1.5, 0.0) + 0.00.1 = 2.5 |
item3 | computer | apple computer | max(0.0, 1.0) + 0.00.1 + max(1.5, 1.0) + 1.00.1 = 2.6 |
前の演習で予想と異なり、item1が先頭に来てしまうのは、titleフィールドに出現する単語数がcomputer > appleとなることで、IDFが効き過ぎてしまっているためです。以下の手順でこの「効き過ぎ」を解消し、再度同じ検索、次いでtieパラメーターを使って検索し、結果を比較します。
<similarity class="solr.ClassicSimilarityFactory"/>
ls *.txt
ls *-1.0-SNAPSHOT*
{
"id": 1,
"category": "コミュニティ関連施設",
"name": "市民活動サポートセンター",
"hierarchy": "市民利用施設/市民文化・社会教育系施設/コミュニティ関連施設/市民活動サポートセンター",
"address": "浦和区東高砂町11番1",
"location": "35.858694,139.659134"
}
以降の演習では、nameフィールドで「部分一致検索」「前方一致検索」「後方一致検索」を行ってみます。「プラザ」を部分一致で検索するために、name_2gフィールドに対して「プラザ」を検索してみましょう。以下のようにパラメーターを設定し、「プラザ」を部分一致検索してください。
次に、前方一致検索するために、name_forwardフィールドに対して「プラザ」を検索してみましょう。以下のようにパラメーターを設定して検索します。
Solr Admin UIのAnalysisを使って、name_forward(text_forward)フィールドの動作を確認してみましょう。
<fieldType name="text_forward" class="solr.TextField" positionIncrementGap="100">
<analyzer type="index">
<tokenizer class="solr.EdgeNGramTokenizerFactory" minGramSize="1" maxGramSize="100"/>
# プラザイースト → プ、プラ、プラザ、プラザイ、プラザイー、プラザイース、プラザイースト
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
<analyzer type="query">
<tokenizer class="solr.KeywordTokenizerFactory"/>
# プラザ → プラザ
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
</fieldType>
<fieldType name="text_backward" class="solr.TextField" positionIncrementGap="100">
<analyzer type="index">
<tokenizer class="solr.KeywordTokenizerFactory"/>
# ワークプラザ →
<filter class="solr.ReverseStringFilterFactory"/>
# → ザラプクーワ
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.EdgeNGramFilterFactory" minGramSize="1" maxGramSize="100"/>
# → ザ、ザラ、ザラプ、ザラプク、ザラプクー、ザラプクーワ
</analyzer>
<analyzer type="query">
# プラザ →
<tokenizer class="solr.KeywordTokenizerFactory"/>
<filter class="solr.ReverseStringFilterFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
# → ザラプ
</analyzer>
</fieldType>
では実際に、後方一致検索をするために、name_backwardフィールドに対して「プラザ」や「センター」を検索してみましょう。以下のようにパラメーターを設定して検索します。
Solr Admin UIのAnalysisを使って、name_backward(text_backward)フィールドの動作を確認してみましょう。
さらに、Schemaでname_backwardを選択し、Load Term Infoにてトップ100個ほどの単語を表示させて、文字順が逆転してインデクシングされていることを確認します。
Apache Solr にはランダムソート用にrandomというフィールド型があり、下記のような設定と検索時のソートパラメーター指定だけで動作します。
設定
<fieldType name="random" class="solr.RandomSortField" indexed="true"/>
<dynamicField name="random_*" type="random" />
- 検索時のソートパラメーター指定:sort=random_<乱数> desc
- しくみ:randomフィールドでソートが指定されると、文書毎に「フィールド名+文書ID+インデックスバージョン」をシードにした乱数が計算されて当該フィールドに動的に割り当てられます。これにより、<乱数>の部分を適当なタイミングで切り替えるだけで、ランダムソートによる検索結果順の切り替えタイミングを自由に制御できます。
KandaSearch のライブラリーからECサイトのデータとconfigを入手し、コレクションecを作成して、ECサイトデータをインデクシングします。その上で以下のように指定して通常の検索とランダムソート付き検索を試してみましょう。
ID | 文書 | トークン | |
---|---|---|---|
1 | りんご(青森県産) | /果物/りんご | ⇒ /果物, /果物/りんご |
2 | りんご(山形県産) | /果物/りんご | ⇒ /果物, /果物/りんご |
3 | みかん(和歌山県産) | /果物/みかん | ⇒ /果物, /果物/みかん |
4 | みかん(愛媛県産) | /果物/みかん | ⇒ /果物, /果物/みかん |
5 | ぶどう(山梨県産) | /果物/ぶどう | ⇒ /果物, /果物/ぶどう |
"/果物", 5, 果物 (5)
"/果物/りんご", 2, └りんご (2)
"/果物/みかん", 2, └みかん (2)
"/果物/ぶどう", 1 └ぶどう (1)
Solr Admin UIのAnalysisを使って、PathHierarchyTokenizerの動作を確認しましょう。コレクションはecまたはgeospatialのどちらかを使います。
<fieldType name="pathhie" class="solr.TextField">
<analyzer type="index">
<tokenizer class="solr.PathHierarchyTokenizerFactory" delimiter="/"/>
</analyzer>
<analyzer type="query">
<tokenizer class="solr.KeywordTokenizerFactory"/>
</analyzer>
</fieldType>
ここではecコレクションを使ってカテゴリー階層を考慮したファセットの動作を確認します(geospatialコレクションの場合、hierarchyフィールドが階層ファセットになります)。
geospatialまたはecコレクションで試すことができます。KandaSearch UIの検索のSUGGESTタブに設定するだけで試すことができます。defTypeはどちらもedismaxとします。
Apache Solr 提供のサジェスチョン機能は、日本語IMEの動作を考慮に入れていないので、日本語入力下でのサジェストがうまく動作しないことが多々あります。
RCSSを使うとこの不具合が解消され、日本語サジェスチョンがうまく動作します。
前の演習で作成したgeospatialコレクションには、さいたま市の公共施設データがその緯度・経度情報と共にインデクシングされています。このコレクションを利用して、下記の手順で地理検索を試します。
(*:*)
します。すると、さいたま市役所から1km以内の公共施設が近い順に表示されます。 リクエストハンドラ(qt):/spatial 任意のパラメーター:pt=35.861648,139.645496spatial=true # 地理検索を実行
fq={!geofilt}
sort=geodist() asc # ptから近い順にソート
sfield=location # 緯度・経度フィールド名
d=1 # 半径1km以内