はじめに
社内で「Elasticsearch ハンズオン」を開催した - kakakakakku blog
http://kakakakakku.hatenablog.com/entry/2015/09/09/231956
をやってみた。緯度経度のデータが入ってたのでKibanaで地図を使いたくなった。
このハンズオン資料で使用している livedoor グルメ
データをconvertする処理を少しいじってkibana / Elasticsearch で地図が使えそう。
スクリプト群
https://github.com/imura81gt/elasticsearch-hands-on
forkさせていただきました。
なぜ少しいじるのか
Lat/Lon Formats
https://www.elastic.co/guide/en/elasticsearch/guide/current/lat-lon-formats.html
この3つのフォーマットで地図が使える。
PUT /attractions/restaurant/1
{
"name": "Chipotle Mexican Grill",
"location": "40.715, -74.011"
}
PUT /attractions/restaurant/2
{
"name": "Pala Pizza",
"location": {
"lat": 40.722,
"lon": -73.989
}
}
PUT /attractions/restaurant/3
{
"name": "Mini Munchies Pizza",
"location": [ -73.983, 40.719 ]
}
ハンズオンの資料のままやると以下のようにelasticsearchに格納されて
Kibanaの visualize
- Tile Map
で Geohash
として使えなかった。
(使い方を知らないだけかも…)
{
"id": "6",
(省略)
"north_latitude": "35.38.43.555",
"east_longitude": "139.42.59.224",
(省略)
}
どうやるか
(1)コンバートするスクリプトを修正
(2)mappingファイルも修正
(3)再度indexing
(1)コンバートするスクリプトを修正
- 緯度経度を60進数(度分秒)から10進数に変換する必要があった
- 出力フォーマットも
{"pin":{"lat": "111.111", "lon": "222.222"}
変更
require 'csv'
require 'json'
ES_INDEX_NAME = 'gourmet'
ES_TYPE_NAME = 'restaurants'
row_csv = CSV.read('restaurants.csv')
header = row_csv.slice!(0)
data = row_csv
OUTPUT_FILENAME = 'bulk_restaurants_lat_lon.json'
File.delete(OUTPUT_FILENAME) if File.exist?(OUTPUT_FILENAME)
File.open(OUTPUT_FILENAME, 'a') do |file|
data.each do |row|
index = { index: { _index: ES_INDEX_NAME, _type: ES_TYPE_NAME, _id: row[0] } }
file.puts(JSON.dump(index))
hash = Hash[header.zip(row)]
lon = ""
lat = ""
mod_hash = {}
hash.each do |key, value|
if key == "north_latitude" then
value =~ /([0-9]+)\.([0-9]+)\.(.+)/
lat = ($1.to_f + ($2.to_f / 60) + ($3.to_f / 60**2)).to_s
elsif key == "east_longitude" then
value =~ /([0-9]+)\.([0-9]+)\.(.+)/
lon = ($1.to_f + ($2.to_f / 60) + ($3.to_f / 60**2)).to_s
else
mod_hash[key] = value
end
end
mod_hash["pin"] = {"lat" => lat, "lon" => lon}
file.puts(JSON.dump(mod_hash))
end
end
実行する
$ ruby convert_bulk_data_lat_lon.rb
bulk_restaurants_lat_lon.json が出来ていれば成功
意図したフォーマットになっているか確認
$ head -n 2 bulk_restaurants_lat_lon.json | jq .
{
"index": {
"_index": "gourmet",
"_type": "restaurants",
"_id": "2"
}
}
{
"id": "2",
"name": "ラ・マーレ・ド・茶屋",
"property": "2F・3F",
"alphabet": "LA MAREE DE CHAYA",
"name_kana": "らまーれどちゃや",
"pref_id": "14",
"area_id": "1013",
"station_id1": "2338",
"station_time1": "22",
"station_distance1": "1789",
"station_id2": "2401",
"station_time2": "28",
"station_distance2": "2240",
"station_id3": "2867",
"station_time3": "47",
"station_distance3": "3755",
"category_id1": "201",
"category_id2": "0",
"category_id3": "0",
"category_id4": "0",
"category_id5": "0",
"zip": "240-0113",
"address": "三浦郡葉山町堀内24-3",
"description": "こちら2.3Fのレストランへのコメントになります。 『ラ・マーレ・ド・茶屋』1F(テラス&バー)へのコメントはそちらにお願いします。 駐車場15台(専用) 06/06/19 営業時間等更新(From東京グルメ)",
"purpose": null,
"open_morning": "0",
"open_lunch": "1",
"open_late": "0",
"photo_count": "1",
"special_count": "0",
"menu_count": "0",
"fan_count": "5",
"access_count": "6535",
"created_on": "2000-09-10 11:22:02",
"modified_on": "2011-04-22 16:05:12",
"closed": "0",
"pin": {
"lat": "35.28154611111111",
"lon": "139.57225805555555"
}
}
$
ここチェック。
"pin": {
"lat": "35.28154611111111",
"lon": "139.57225805555555"
}
(2)mappingファイルも修正
$ cp -p elasticsearch-hands-on/mappings/restaurants.json elasticsearch-hands-on/mappings/restaurants_lat_lon.json
ファイルを修正する。
以下の2つは削除。
- north_latitude
- east_longitude
代わりに以下を追加。
$ tail -n 7 elasticsearch-hands-on/mappings/restaurants_lat_lon.json
"pin": {
"type" : "geo_point"
}
}
}
}
}
(3)再度indexing(mapping削除、再登録)
mapping削除
$ curl -X DELETE http://192.168.99.100:19200/gourmet/_mapping/restaurants
index削除
$ curl -X DELETE http://192.168.99.100:19200/gourmet/
再作成
$ curl -X POST http://192.168.99.100:19200/gourmet -d @elasticsearch-hands-on/mappings/restaurants_lat_lon.json
mapping確認
$ curl -X GET http://192.168.99.100:19200/gourmet/restaurants/_mapping\?pretty
kibanaでインデックスを登録している場合は一回削除して作りなおす
再投入
$ curl -X POST http://192.168.99.100:19200/_bulk --data-binary @datasets/bulk_restaurants_lat_lon.json
表示させてみる
pin のとなりに add が表示されるのでクリック。
クリックした後pinをクリックすると Visualize
ボタンが出てくるのでクリック。
表示できた!