Help us understand the problem. What is going on with this article?

Kibana + Elasticsearch で地図を使いたい

More than 3 years have passed since last update.

はじめに

社内で「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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした