Skip to main content
Add more examples and other links in case the first ones will 404 one day...
Source Link

EDIT: In case the previous links become unavailable, here is another version of the same blog posts:

Also here are some content extracted from those sources:

A logstash configuration to read a CSV file using filebeat (but you can replace the input part with whatever source you have):

input { 
  beats {
    port => 5044
  } 
}
filter {
    csv {
      separator => ","
      columns => [
        "id","number","street_name","zipcode","city","source","latitude","longitude"
      ]
      remove_field => [ "message", "host", "@timestamp", "@version", "input", "log", "ecs", "agent", "tags" ]
    }
    mutate {
      convert => { "longitude" => "float" }
      convert => { "latitude" => "float" }
    }
    mutate {
      rename => {
        "longitude" => "[location][lon]"
        "latitude" => "[location][lat]"
        "number" => "[address][number]"
        "street_name" => "[address][street_name]"
        "zipcode" => "[address][zipcode]"
        "city" => "[address][city]"
      }
    }
}
output {
    elasticsearch {
      hosts => ["http://elasticsearch:9200"]
      index => "bano"
      user => "elastic"
      password => "changeme"
      document_id => "%{[id]}"
    }
}

Mapping template you can use when creating the index:

PUT _template/bano
{
  "index_patterns": "bano*",
  "settings": {
    "index.number_of_shards": 1,
    "index.number_of_replicas": 0,
    "index.analysis": {
      "analyzer": {
        "bano_city_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "asciifolding"
          ]
        },
        "bano_street_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "elision",
            "lowercase",
            "asciifolding",
            "bano_synonym"
          ]
        }
      },
      "filter": {
        "bano_synonym": {
          "type": "synonym",
          "synonyms": [
            "bd => boulevard",
            "av => avenue",
            "r => rue",
            "rte => route"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "address": {
        "properties": {
          "city": {
            "type": "text",
            "analyzer": "bano_city_analyzer",
            "fields": {
              "keyword": {
                "type": "keyword"
              }
            }
          },
          "number": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword"
              }
            }
          },
          "street_name": {
            "type": "text",
            "analyzer": "bano_street_analyzer"
          },
          "zipcode": {
            "type": "keyword"
          }
        }
      },
      "id": {
        "type": "keyword"
      },
      "source": {
        "type": "keyword"
      },
      "location": {
        "type": "geo_point"
      }
    }
  }
}

Typical request to find a geo point from a postal address:

GET bano/_search
{
  "size": 1, 
  "query": {
    "multi_match": {
      "query": "6 allée des myrtilles cergy",
      "fields": [
        "address.city",
        "address.street_name",
        "address.number"
      ],
      "type": "most_fields"
    }
  }
}

Typical request to find the closest postal address (and its actual coordinates):

GET bano/_search
{
  "size": 1, 
  "query": {
    "bool": {
      "filter": {
        "geo_distance": {
          "distance": "1km",
          "location": {
            "lat": 49.0409,
            "lon": 2.0178
          }
        }
      }
    }
  },
  "sort": [
    {
      "_geo_distance": {
        "location": {
          "lat": 49.0409,
          "lon": 2.0178
        }
      }
    }
  ]
}

EDIT: In case the previous links become unavailable, here is another version of the same blog posts:

Also here are some content extracted from those sources:

A logstash configuration to read a CSV file using filebeat (but you can replace the input part with whatever source you have):

input { 
  beats {
    port => 5044
  } 
}
filter {
    csv {
      separator => ","
      columns => [
        "id","number","street_name","zipcode","city","source","latitude","longitude"
      ]
      remove_field => [ "message", "host", "@timestamp", "@version", "input", "log", "ecs", "agent", "tags" ]
    }
    mutate {
      convert => { "longitude" => "float" }
      convert => { "latitude" => "float" }
    }
    mutate {
      rename => {
        "longitude" => "[location][lon]"
        "latitude" => "[location][lat]"
        "number" => "[address][number]"
        "street_name" => "[address][street_name]"
        "zipcode" => "[address][zipcode]"
        "city" => "[address][city]"
      }
    }
}
output {
    elasticsearch {
      hosts => ["http://elasticsearch:9200"]
      index => "bano"
      user => "elastic"
      password => "changeme"
      document_id => "%{[id]}"
    }
}

Mapping template you can use when creating the index:

PUT _template/bano
{
  "index_patterns": "bano*",
  "settings": {
    "index.number_of_shards": 1,
    "index.number_of_replicas": 0,
    "index.analysis": {
      "analyzer": {
        "bano_city_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "asciifolding"
          ]
        },
        "bano_street_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "elision",
            "lowercase",
            "asciifolding",
            "bano_synonym"
          ]
        }
      },
      "filter": {
        "bano_synonym": {
          "type": "synonym",
          "synonyms": [
            "bd => boulevard",
            "av => avenue",
            "r => rue",
            "rte => route"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "address": {
        "properties": {
          "city": {
            "type": "text",
            "analyzer": "bano_city_analyzer",
            "fields": {
              "keyword": {
                "type": "keyword"
              }
            }
          },
          "number": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword"
              }
            }
          },
          "street_name": {
            "type": "text",
            "analyzer": "bano_street_analyzer"
          },
          "zipcode": {
            "type": "keyword"
          }
        }
      },
      "id": {
        "type": "keyword"
      },
      "source": {
        "type": "keyword"
      },
      "location": {
        "type": "geo_point"
      }
    }
  }
}

Typical request to find a geo point from a postal address:

GET bano/_search
{
  "size": 1, 
  "query": {
    "multi_match": {
      "query": "6 allée des myrtilles cergy",
      "fields": [
        "address.city",
        "address.street_name",
        "address.number"
      ],
      "type": "most_fields"
    }
  }
}

Typical request to find the closest postal address (and its actual coordinates):

GET bano/_search
{
  "size": 1, 
  "query": {
    "bool": {
      "filter": {
        "geo_distance": {
          "distance": "1km",
          "location": {
            "lat": 49.0409,
            "lon": 2.0178
          }
        }
      }
    }
  },
  "sort": [
    {
      "_geo_distance": {
        "location": {
          "lat": 49.0409,
          "lon": 2.0178
        }
      }
    }
  ]
}
Source Link

Let me link to some blog posts I wrote about that:

I gave a demo of this during a talk recently. Here is the link to the source code I used for that: https://github.com/dadoonet/bano-elastic/

Hope this helps.