LoginSignup
16
15

More than 5 years have passed since last update.

Kibana + Elasticsearch で地図を使いたい

Last updated at Posted at 2015-09-18

はじめに

社内で「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つのフォーマットで地図が使える。

format
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 MapGeohash として使えなかった。
(使い方を知らないだけかも…)

bulk_restaurants.json
{
  "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"} 変更
convert_bulk_data_lat_lon.rb
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

実行する

convert
$  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でインデックスを登録している場合は一回削除して作りなおす

kibana_index.png

再投入

$ curl -X POST http://192.168.99.100:19200/_bulk --data-binary @datasets/bulk_restaurants_lat_lon.json

表示させてみる

pin のとなりに add が表示されるのでクリック。
クリックした後pinをクリックすると Visualize ボタンが出てくるのでクリック。

0001_Discover_-_Kibana_4.png

表示できた!

0002_Visualize_-_Kibana_4.png

16
15
1

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
16
15