Dane

Na potrzeby tego zadania skorzystałem z danych pochodzących ze strony http://www.vdstech.com/world-data.aspx. Wybrałem dane Places z podkategorii Population. Tak pobrane dane zostały przerobione na geojson przy pomocy http://ogre.adc4gis.com/. Oryginalny plik posiada ponad 200 000 wpisów, na potrzeby poprawnego wyświetlenia całości pozwoliłem sobie zmniejszyć ten zbiór do 3344 rekordów. Tak pomniejszone dane zostały zapisane do pliku Places.small.geojson i wyglądają następująco:

Przykładowy rekord

{
        "type": "Feature",
        "properties": {
            "CODE": "AL105",
            "CODE_DESC": "Settlement",
            "NAME": null,
            "TEXT": "SPEIGHTSTOWN"
        },
        "geometry": {
            "type": "Point",
            "coordinates": [-59.64211654663086, 13.240438461303711]
        }
}

ElasticSearch 5.2.2

Pierw należy utworzyć odpowiedni mapping dla indeksu places.small

curl -XPUT http://localhost:9200/places.small -d "{\"mappings\": {\"place\": {\"properties\": {\"CODE\": {\"type\": \"string\"},\"CODE_DESC\": {\"type\": \"string\"},\"NAME\": {\"type\": \"string\"},\"TEXT\": {\"type\": \"string\"},\"location\": {\"type\": \"geo_point\" }}}}}"

Następnie należy przygotować dane do dalszej obróbki w ElasticSearch

jq-win64.exe --compact-output ".features[] | (.geometry.coordinates | map( .*1000|floor|./1000)) as $a | .properties |= .+ {location: $a} | .properties" Places.small.geojson > Places.small.js

< Places.small.js jq-win64.exe --compact-output "{ \"index\": { \"_type\": \"place\" } }, ." > Places.small.bulk

Tak przygotowane dane są gotowe do załadowania

curl -XPUT localhost:9200/places.small/_bulk --data-binary @places.small.bulk

Sprawdzamy czy dane zostały poprawnie wczytane

curl -XGET localhost:9200/places.small/_count
{"count":3344,"_shards":{"total":5,"successful":5,"failed":0}}

Poszukajmy miejsca o nazwie MABARUMA

curl -s "http://localhost:9208/places.small/place/_search?pretty=true&q=TEXT:MABARUMA" | jq-win64.exe .hits.hits[].\"_source\"

Output:

"hits" : [
      {
        "_index" : "places",
        "_type" : "place",
        "_id" : "AVsPltw9UfJIYBgww_Jh",
        "_score" : 6.7703557,
        "_source" : {
          "CODE" : "AL105",
          "CODE_DESC" : "Settlement",
          "NAME" : null,
          "TEXT" : "MABARUMA",
          "location" : [
            -59.778,
            8.202
          ]
        }
      }
    ]

Przeszukiwanie w promieniu 700km od miasteczka MADRUSAH [24.858, 14.527]

curl -XGET localhost:9200/places.small/place/_search?pretty -d "{\"size\":5000,\"query\":{\"bool\":{\"must\":{\"match_all\":{}}, \"filter\":{\"geo_distance\":{\"distance\":\"700km\",\"location\":{\"lat\":24.858,\"lon\":14.527}}}}}}" | jq-win64.exe .hits.hits[]._source | jq-win64.exe "{type:\"Feature\", properties: {CODE, CODE_DESC, NAME, TEXT}, geometry: {type:\"Point\", coordinates: .location}}" | jq-win64.exe --slurp . | jq-win64.exe {type:\"FeatureCollection\",features:.} > map1.geojson

Polygon pomiędzy miejscowościami : MPAL, TCHILMAKHA, NAMARI, THIEOGNI.

curl -XGET localhost:9200/places.small/place/_search?pretty -d "{\"size\":5000,\"query\":{\"bool\":{\"must\":{\"match_all\":{}}, \"filter\":{\"geo_polygon\":{\"location\":{\"points\":[[ -16.260, 15.926],[ -16.249, 15.033],[ -13.643, 15.082],[ -13.591, 15.965]]}}}}}}" | jq-win64.exe .hits.hits[]._source | jq-win64.exe "{type:\"Feature\", properties: {CODE, CODE_DESC, NAME, TEXT}, geometry: {type:\"Point\", coordinates: .location}}" | jq-win64.exe --slurp . | jq-win64.exe {type:\"FeatureCollection\",features:.} > map2.geojson

MongoDB 3.4.3

Przerobienie pliku places.small.geojson tak aby dało się go zaimportować

jq-win64.exe ".features" places.small.geojson > places.small.list.geojson

Import danych do bazy

mongoimport --drop -d test -c places --jsonArray < places.small.list.geojson

Sprawdzenie danych w bazie

> db.places.findOne()
{
        "_id" : ObjectId("58de84d32e5a9a59b6dbdffb"),
        "type" : "Feature",
        "properties" : {
                "CODE" : "AL105",
                "CODE_DESC" : "Settlement",
                "NAME" : null,
                "TEXT" : null
        },
        "geometry" : {
                "type" : "Point",
                "coordinates" : [
                        -59.5754508972168,
                        13.28094482421875
                ]
        }
}

Usunięcie zbędnego pola Name które było puste w wybranych rekordach

db.places.updateMany({type: "Feature"}, {$unset: {"properties.NAME":""}})
{ "acknowledged" : true, "matchedCount" : 3344, "modifiedCount" : 3344 }

Ustawienie indeksu aby można było korzystać z geospatial queries

> db.places.ensureIndex({"geometry" : "2dsphere"})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}

W pliku skrypt.js umieszczono polecenie znajdujące 700 najbliższych punktów od miejscowości MADRUSAH [14.5271244, 24.8589076]

printjson( db.places.find({ "geometry": {$near: {$geometry: {type: "Point", coordinates: [14.5271244, 24.8589076]}}}}, {_id: 0}).limit(700).toArray())

Tak wywołany skrypt utworzył plik mongoNear.json

mongo test skrypt.js > mongoNear.json

Następnie mongoNear.json został przekształcony w mongoNear.geojson za pomocą jq

type mongoNear.json | findstr /v MongoDB | findstr /v mongodb | ^jq-win64.exe {type:\"FeatureCollection\",features:.} > mongoNear.geojson
Plik mongoNear.geojson wygląda następująco: