Apache Solr

 

solrでSpatialSearchするためのschema.xml設定(LatLonType)

solrで空間検索(Spatial Search)するためのschema.xmlの設定の解説です。設定の仕方と、そのフィールドへのデータの追加の仕方・使い方についても解説します。多少解りづらい設定なので注意しましょう。

新サイト、tree-mapsを公開しました!!

tree-maps: 地図のWEB TOOLの事ならtree-mapsにお任せ!

地図に関するWEB TOOL専門サイトです!!

大画面で大量の緯度経度を一気にプロット、ジオコーディング、DMS<->DEGの相互変換等ができます!

◯ 広告

Spatial Searchは、位置情報を使って空間検索する機能です。

緯度・経度を使って、中心点から半径Nkm以内で検索し、中心点から距離が近い順にソート、等が可能です。

必要な設定のみを抽出しました。

<schema name="address" version="1.5">
    <types>
        <fieldType name="tdouble" class="solr.TrieDoubleField" sortMissingLast="true" precisionStep="8" positionIncrementGap="0"/>
        <fieldType name="location" class="solr.LatLonType" subFieldSuffix="_coordinate"/>
    </types>

    <fields>
        <field name="latlng" type="location" indexed="true" stored="false" multiValued="false"/>
        <dynamicField name="*_coordinate" type="tdouble" indexed="true" stored="false" />
    </fields>
</schema>

最低限必要なのはこれだけです。

dynamicFieldの「*_coordinate」ですが、そういうフィールドを自分で用意するのではないので注意です。

フィールドとして用意するのは「latlng」の方です。latlngという名前は私が勝手に命名しているだけです。

このlatlngフィールドですが、型は「string」となります。

latlngフィールドは検索用しか使い道が無いので、storedはfalseです。

ドキュメントには以下のようにList型で文字列を指定して定義します。

schema.xmlの「latlng」フィールドは、以下の「String latlng」が対応しています。

package tree.solr.search.address;

import java.util.List;

import org.apache.solr.client.solrj.beans.Field;

/**
 * 住所インデックスのドキュメントです。
 * @author tree
 */
public class AddressDocument {

    @Field(AddressDocumentNames.ID)
    public String id;

    @Field(AddressDocumentNames.LATLNG)
    public String latlng;
}
AddressDocument doc = new AddressDocument();
doc.id = String.valueOf(address.prefCd + address.cityCd + address.townStreetCd);
doc.latlng = address.latitude + "," + address.longitude;
return doc;

ここが大変解り難い箇所です。

「緯度」「半角カンマ」「軽度」という連結文字列をlatlngに設定しています

solr wikiに書いてありませんが、このような連結文字列を1つのフィールドに設定します。

schema.xmlではstored=falseにしていましたが、どんな値が入るか確認するため、stored=trueにします。

まずはstoredデータを確認します。

<response>
<lst name="responseHeader">
<int name="status">0</int>
<int name="QTime">2</int>
<lst name="params">
<str name="fl">latlng</str>
<str name="q">*:*</str>
<str name="wt">xml</str>
</lst>
</lst>
<result name="response" numFound="253851" start="0">
<doc>
<str name="latlng">43.040237,141.304668</str>
</doc>
<doc>
<str name="latlng">43.044979,141.304846</str>
</doc>
<doc>
<str name="latlng">43.041677,141.300397</str>
</doc>
<doc>
<str name="latlng">43.058257,141.312369</str>
</doc>
<doc>
<str name="latlng">43.050177,141.287485</str>
</doc>
<doc>
<str name="latlng">43.061658,141.310427</str>
</doc>
<doc>
<str name="latlng">43.058889,141.30853</str>
</doc>
<doc>
<str name="latlng">43.054302,141.302979</str>
</doc>
<doc>
<str name="latlng">43.046518,141.295128</str>
</doc>
<doc>
<str name="latlng">43.065734,141.308901</str>
</doc>
</result>
</response>

先ほど設定した連結文字列が設定されています。

続いて、indexedデータを確認します。

latlngフィールドのindexedデータ

latlngフィールドにindexedデータは設定されていないようです

代わりに「latlng_0_coordinate」「latlng_1_coordinate」というフィールドが自動的に生成されています。

latlng_0_coordinateフィールドのindexedデータ

データの中身から察すると、latlng_0_coordinateは緯度のindexedデータのようです。

latlng_1_coordinateフィールドのindexedデータ

続いて、latlng_1_coordinateは軽度のindexedデータのようです。

schema.xmlで設定した以下の部分は、「latlng_0_coordinate」と「latlng_1_coordinate」に適用されています。

<dynamicField name="*_coordinate" type="tdouble" indexed="true" stored="false" />

0と1という数字はどこで設定しているのでしょうね。暗黙の定数値かもしれません。

この記事は設定についての解説がメインなので、詳細な検索については述べません。

JR秋葉原駅の座標から、半径1km以内をサークル(円形)検索し、距離の近い順にソート、というクエリを発行します。

http://localhost:8080/solr-server/address/select?q=*:*&fq={!geofilt}&sfield=latlng&pt=35.698683,139.774219&d=10&sort=geodist() asc&fl=latlng

latlngフィールドを指定すると、自動的に「latlng_0_coordinate」と「latlng_1_coordinate」で検索されるようです。

クエリの結果は以下の通りです。

<response>
<lst name="responseHeader">
<int name="status">0</int>
<int name="QTime">0</int>
<lst name="params">
<str name="d">10</str>
<str name="sort">geodist() asc</str>
<str name="fl">latlng</str>
<arr name="q">
<str>*:*</str>
</arr>
<str name="sfield">latlng</str>
<str name="pt">35.698683,139.774219</str>
<str name="fq">{!geofilt}</str>
</lst>
</lst>
<result name="response" numFound="1721" start="0">
<doc>
<str name="latlng">35.699092,139.77448</str>
</doc>
<doc>
<str name="latlng">35.699659,139.773818</str>
</doc>
<doc>
<str name="latlng">35.697321,139.774085</str>
</doc>
<doc>
<str name="latlng">35.698071,139.776265</str>
</doc>
<doc>
<str name="latlng">35.697735,139.776175</str>
</doc>
<doc>
<str name="latlng">35.700873,139.774364</str>
</doc>
<doc>
<str name="latlng">35.700764,139.772721</str>
</doc>
<doc>
<str name="latlng">35.697103,139.776492</str>
</doc>
<doc>
<str name="latlng">35.701011,139.77517</str>
</doc>
<doc>
<str name="latlng">35.696159,139.773758</str>
</doc>
</result>
</response>

これら緯度・経度を地図にプロットしてみます。

SpatialSearchで距離が近い順のプロット

秋葉原駅から距離の近い順に1〜10まで表示されていますね。

続いてサークル検索になっているかどうか、大量にプロットして確認してみましょう。

以下は秋葉原駅から2km圏内のデータを最大168件プロットした例です。

SpatialSearchのサークル検索

サークル(丸)検索になってますね!!


Spatial Searchの結果を簡単に確認できるように「複数の緯度経度を地図にプロットする」を用意しました!

◯ 広告