LoginSignup
11
18

More than 5 years have passed since last update.

Elasticsearch でスキーマを指定して空間検索をする

Posted at

Elasticsearch でスキーマを定義してデータを投入する方法を試してみます。
Elasticsearch のインストールについてはコチラ
kuromoji のインストーラについてはコチラを参考にしてください。

Elasticsearch のスキーマについて

Elasticsearch ではスキーマを マッピング、型を タイプ という概念で扱います。
マッピングを定義していない場合は、投入されたデータの値からタイプを自動で判定して、マッピングされます。
これはとても便利な機能である反面、意図しない・不必要なインデクシングが発生してしまう可能性もあります。
安定した運用が求められるケースでは、しっかりとスキーマを定義したほうが良いですね。

マッピングの指定

今回はランドマークの「名前緯度軽度説明」を投入してみます。

項目 プロパティ名 説明
名前 name ランドマークの名前。全文検索対象外
緯度軽度 coord ランドマークの緯度軽度。空間検索の対象
説明 description ランドマークの説明。全文検索の対象

これをマッピング指定に用いる JSON で表現すると以下のようになります。

mapping.json
{
    "mappings": {
        "sample": {
            "properties": {
                "name": {
                    "type": "string",
                    "index": "not_analyzed"
                },
                "coord": {
                    "type": "geo_point"
                },
                "description": {
                    "type": "string",
                    "analyzer": "kuromoji"
                }
            }
        }
    }
}

この JSON を使って landmark というインデックスを作成します。

$ curl -X PUT http://localhost:9200/landmark --data-binary @mapping.json

意図通り定義されたかを確認してみます。

$ curl -X GET http://localhost:9200/landmark
{
    "landmark": {
        "aliases": {},
        "mappings": {
            "sample": {
                "properties": {
                    "coord": {
                        "type": "geo_point"
                    },
                    "description": {
                        "type": "string",
                        "analyzer": "kuromoji"
                    },
                    "name": {
                        "type": "string",
                        "index": "not_analyzed"
                    }
                }
            }
        },
        ...
    }
}

いい感じですね。

データの投入

前回同様、Bulk API を使ってデータを投入します。
以下の JSON を使います。

landmark.json
{ "index" : {} }
{ "name": "スカイツリー", "coord": { "lat": "35.710063", "lon": "139.8107"}, "description": "東京スカイツリー(とうきょうスカイツリー、英: TOKYO SKYTREE)は東京都墨田区押上一丁目にある電波塔(送信所)である。"}
{ "index" : {} }
{ "name": "BLUE NOTE TOKYO", "coord": { "lat": "35.661198", "lon": "139.716207"}, "description": "N.Y.の「Blue Note」を本店に持つジャズクラブとして、南青山にオープンしたブルーノート東京。ジャズをはじめとする多様な音楽ジャンルのトップアーティストたちが、連夜渾身のプレイを繰り広げている。"}
{ "index" : {} }
{ "name": "東京タワー", "coord": { "lat": "35.65858", "lon": "139.745433"}, "description": "東京タワー(とうきょうタワー、英: Tokyo Tower)は、東京都港区芝公園にある総合電波塔とその愛称である。正式名称は日本電波塔(にっぽんでんぱとう)。"}

API にデータを食わせます。

$ curl -X POST http://localhost:9200/landmark/sample/_bulk --data-binary @landmark.json

データの検索

「ジャズ」で検索してみます。

$ curl -X GET http://localhost:9200/landmark/sample/_search -d '{"query":{"match":{"description":"ジャズ"}}}'
{
    ...
    "hits": {
        "total": 1,
        "max_score": 0.081366636,
        "hits": [
            {
                "_index": "landmark",
                "_type": "sample",
                "_id": "AU071ik4RTPkdK_mzpPE",
                "_score": 0.081366636,
                "_source": {
                    "name": "BLUE NOTE TOKYO",
                    "coord": {
                        "lat": "35.661198",
                        "lon": "139.716207"
                    },
                    "description": "N.Y.の「Blue Note」を本店に持つジャズクラブとして、南青山にオープンしたブルーノート東京。ジャズをはじめとする多様な音楽ジャンルのトップアーティストたちが、連夜渾身のプレイを繰り広げている。"
                }
            }
        ]
    }
}

ちゃんと検索されました。

次に空間検索をしてみます。
「渋谷駅から近い順」に検索してみましょう。
(緯度経度は GoogleMap などから取得すると良いです)

query.json
{
    "sort": [
        {
            "_geo_distance": {
                "coord": {
                    "lat": 35.658517,
                    "lon": 139.701334
                },
                "order": "asc"
            }
        }
    ],
    "query": {
        "filtered": {
            "query": {
                "match_all": {}
            }
        }
    }
}
$ curl -X GET http://localhost:9200/landmark/sample/_search --data-binary @query.json

レスポンスはこんな感じです。

{
    ...
    "hits": {
        "total": 3,
        "max_score": null,
        "hits": [
            {
                ...
                "_source": {
                    "name": "BLUE NOTE TOKYO",
                    "coord": {
                        "lat": "35.661198",
                        "lon": "139.716207"
                    },
                    ...
                },
                "sort": [
                    1376.353778271321
                ]
            },
            {
                ...
                "_source": {
                    "name": "東京タワー",
                    "coord": {
                        "lat": "35.65858",
                        "lon": "139.745433"
                    },
                    ...
                },
                "sort": [
                    3984.1379076620046
                ]
            },
            {
                ...
                "_source": {
                    "name": "スカイツリー",
                    "coord": {
                        "lat": "35.710063",
                        "lon": "139.8107"
                    },
                    ...
                "sort": [
                    11419.980751959736
                ]
            }
        ]
    }
}

地点間の直線距離が計算され、それの照準で返却されています。
もちろんワード指定の検索と組み合わせることも可能ですので、色々と試してみてください。

11
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
18