elasticsearch导入json数据

导入json数据到es

  • 每条记录必须有一条对应的index声明。json文件应符合Bulk API要求
  • json文件中每条数据前需包含index信息(index/type/id...)
curl -H 'Content-Type: application/x-ndjson'  -s -XPOST localhost:9200/_bulk --data-binary @accounts.json
{"index":{"_index":"index2","_type":"type2","_id":0}}
{"age":10,"name":"jim"}
    {"index":{"_index":"index2","_type":"type2","_id":1}}
{"age":16,"name":"tom"}
  • 若导入文件中为同一个index(/index/type),则可在url中声明默认index(/index/type),则json文件中无须声明index和type,同时,支持部分记录显示声明index和type。
curl -H 'Content-Type: application/x-ndjson'  -s -XPOST localhost:9200/index1/_bulk --data-binary @accounts.json #URL中声明默认index
curl -H 'Content-Type: application/x-ndjson'  -s -XPOST localhost:9200/index1/type1/_bulk --data-binary @accounts.json #URL中声明默认index/type
{"index":{}
{"age":6,"name":"bob"}
{"index":{"_id":"2"}}
{"age":10,"name":"jim"}
{"index":{"_id":"6"}}
{"index":{"_type":"type2","_id":1}}
{"age":16,"name":"tom"}
{"index":{"_index":"index2","_type":"type3","_id":1}}
{"age":20,"name":"lucy"}
  • 可直接导入符合格式要求的json,无须事先创建mapping,es可根据json数据自动创建。
    也可事先声明mapping,,进行自定义设置
  • curl命令导入示例

导入shapefile到es

查阅众多资料后,理论上有如下几种方式:

  1. 使用GDAL直接将shapefile导入ES,失败
  2. 使用GDAL(或ArcMap)将shapefile导成json文件,使用curl命令导入json文件
    说明:生成的json文件格式不符合Bulk API要求,需处理后方能导入
  3. 使用Arcpy编写脚本,将shapefile导出成符合Bulk要求的json,再使用curl命令导入(或脚本实现)
  4. 使用ArcMap导出geojson(或使用Arcpy),使用python(java)解析json文件,使用Bulk API编写脚本导入ES

其中需注意的问题为:

  1. 使用GDAL或ArcMap导出的geojson格式Bulk API要求的数据格式不同
  2. 数据需符合Geo-shape datatypeGeo-point datatype方能使用curl命令导入

综上,最终选择使用第4种方法解决,使用GDAL将shapefile导出成geojson文件,再使用python elasticsearch bulk API编写脚本,解析geojson并导入ES。

1. shapefile to es(失败)

GDAL for ES Driver提供shapefile直接导入ES的方法,但导入时报错

ogr2ogr -f "ElasticSearch" http://localhost:9200 my_shapefile.shp

#ERROR 1: HTTP error code : 405
#ERROR 8: Could not connect to server
#ElasticSearch driver failed to create http://localhost:9200/

2. 通过json文件中转(需处理json文件格式)

另外一种方式为使用ogr2ogr工具将shapefile转换为geojson文件,再将geojson文件导入ES。

2.1 shapefile to geojson

How to convert and import Arc Shapefile from Zillow into an elastic search database?
Ask

ogr2ogr -f GeoJSON  map1.geojson map.shp

生成的json文件格式如下,不包含index信息,Bulk API无法直接导入。

{
"type": "FeatureCollection",
                                                                                
"features": [
{ "type": "Feature", "properties": { "ID_0": 45, "NAME_1": "Anhui" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 119.632111, 31.139344000000108 ], [ 119.644439000000148, 31.115657 ], [ 119.624672, 31.084624000000133 ] ] ] } } 
{ "type": "Feature", "properties": { "ID_0": 45, "NAME_1": "Beijing" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 117.379737, 40.226871 ], [ 117.382896, 40.208718000000147 ], [ 117.369484, 40.190997 ] ] ] } }
]
}

2.2 create index mapping

Indexing Geo Shapes
可针对geo字段和重点字段进行mapping,其余字段导入时自动生成。

PUT /gis1
{
  "mappings": {
    "province1": {
       "properties": {
          "location": {
             "type": "geo_shape"
          },          
          "ID_0": {
             "type": "text"
          },
            "NAME_1": {
             "type": "text"
          }
       }
    }
  }
}

2.3 import json

curl -H 'Content-Type: application/x-ndjson' -XPOST 'http://localhost:9200/gis1/province1/_bulk?pretty' --data-binary @map1.geojson

#报错:"type":"json_e_o_f_exception","reason":"Unexpected end-of-input: expected close marker for Object (start marker at [Source: org.elasticsearch.transport.netty4.ByteBufStreamInput@1ffa375d; line: 1, column: 1])\n at [Source: org.elasticsearch.transport.netty4.ByteBufStreamInput@1ffa375d; line: 1, column: 3]"

需将数据改造成如下格式后,再使用bulk命令导入。

{"index":{"_id":"1"}}
{ "type": "Feature", "properties": { "ID_0": 45, "NAME_1": "Zhejiang" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 121.187362, 27.86903100000012 ], [ 121.190140000000156, 27.847919 ], [ 121.156249, 27.823749000000134 ]] ] ] } }
{"index":{"_id":"2"}}
{ "type": "Feature", "properties": { "ID_0": 46, "NAME_1": "Jiangsu" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 121.187362, 27.86903100000012 ], [ 121.190140000000156, 27.847919 ], [ 121.156249, 27.823749000000134 ]] ] ] } }

4. python脚本导入GDAL生成的geojson文件

# rasa 20180212
# 使用ES python api插入geojson面数据(map.geojson)

import json
from elasticsearch import Elasticsearch
from elasticsearch.helpers import bulk


def set_mapping(es, index_name="content_engine", doc_type_name="en"):
    my_mapping = {
        doc_type_name: {
            "properties": {
                "location": {
                    "type": "geo_shape"
                },
                "ID_0": {
                    "type": "text"
                },
                "NAME_1": {
                    "type": "text"
                }
            }
        }
    }

    # ignore 404 and 400
    es.indices.delete(index=index_name, ignore=[400, 404])
    print("delete_index")

    # ignore 400 cause by IndexAlreadyExistsException when creating an index
    create_index = es.indices.create(index=index_name, ignore=400)
    mapping_index = es.indices.put_mapping(index=index_name, doc_type=doc_type_name, body=my_mapping)
    if create_index["acknowledged"] is not True or mapping_index["acknowledged"] is not True:
        print("Index creation failed...")


def set_data(es, input_file, index_name, doc_type_name="en"):
    with open(input_file, 'r') as f:
        data = json.load(f)

    features = data["features"]

    ACTIONS = []
    i = 0
    count = 0

    for feature in features:
        action = {}

        if (feature["geometry"]["type"] == "Polygon"):  # 判断geometry类型为polygon
            action = {
                "_index": index_name,
                "_type": doc_type_name,
                "_source": {
                    "ID_0": feature["properties"]["ID_0"],
                    "NAME_1": feature["properties"]["NAME_1"],
                    "location": {
                        "type": "polygon",
                        "coordinates": feature["geometry"]["coordinates"]
                    }
                }
            }
        else:  # geometry类型为multipolygon
            action = {
                "_index": index_name,
                "_type": doc_type_name,
                "_source": {
                    "ID_0": feature["properties"]["ID_0"],
                    "NAME_1": feature["properties"]["NAME_1"],
                    "location": {
                        "type": "multipolygon",
                        "coordinates": feature["geometry"]["coordinates"]
                    }
                }
            }

        i += 1
        print("prepare insert:  %s" % feature["properties"]["NAME_1"])
        print("type:  %s" % feature["geometry"]["type"])
        ACTIONS.append(action)
        if (i == 5):
            success, _ = bulk(es, ACTIONS, index=index_name, raise_on_error=True)
            count += success
            i = 0
            ACTIONS = []
            print("insert %s lines" % count)

    success, _ = bulk(es, ACTIONS, index=index_name, raise_on_error=True)
    count += success
    print("insert %s lines" % count)


if __name__ == '__main__':
    # es = Elasticsearch(hosts=["127.0.0.1:9200"], http_auth=('elastic','changeme'),timeout=5000)
    es = Elasticsearch(hosts=["127.0.0.1:9200"], timeout=5000)
    set_mapping(es, "gis6", "province")

    # geojson文件为ogr2ogr生成格式

    # set_data(es, "./data/map-fujian.geojson", "gis6", "province")  # multipolygon
    # set_data(es, "./data/map-anhui.geojson", "gis6", "province") # polygon
    set_data(es, "./data/map-full.geojson", "gis6", "province")  # polygon & multipolygon
    # set_data(es, "./data/map.geojson", "gis6", "province")       # polygon

问题

1.使用python bulk导入multipolygon时报错:Invalid LinearRing found. Found a single coordinate when expecting a coordinate array

sourcecode 638行

原因

  • 同一个geojson文件中存在存在类型为polygon和multipolygon的feature
  • 设定mapping为polygon,插入multipolygon数据会报错:
    invalid number of points in LinearRing (found [1] - must be >= [4]);
  • 设定mapping为multipolygon,插入polygon数据会报错:
    Invalid LinearRing found. Found a single coordinate when expecting a coordinate array

解决方法
判断feature的类型,创建的mapping不同,ES支持同一个type中同时存储polygon/multipolygon

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容