Logstash:运用 Elasticsearch filter 来丰富地理数据

743 阅读5分钟

我们知道丰富数据对于很多的应用来说非常重要。这涉及到访问不同的表格,并进行搜索匹配。找到最为相近的结果并进行丰富数据。针对 Elasticsearh 来说,我们可以通过 enrich processor来进行丰富。你可以阅读我之前的文章来了解更多:

事实上,我们甚至可以在 Logstash 的 pipeline 中采用 Elasticsearch filter 来丰富数据。你可以参考我之前的文章 “Logstash:运用 Elasticsearch 过滤器来丰富数据”。

在今天的文章中,我来采用一个简单的例子来展示如何使用 Elasticsearch filter 来丰富地理数据。这个在实际的使用中非常有用。比如你采集的数据含有传感器 id,但是在采集的数据里可能并不包含地理位置信息。我们可以通过 Elasticsearch filter 来丰富数据的地理位置信息,这样可以在地图上进行展示。

安装

如果你还没有安装好自己的 Elasticsearch 及 Kibana,请参考文章:

在安装的时候,请参考 Elastic Stack 8.x 的安装指南进行安装。

在 Elasticsearch 中创建 enrich 索引

我们在 Elasticsearch 中创建一个可以在 Logstash 中被引用的索引。它的 mapping 是这样的:

`

1.  PUT myindex
2.  {
3.    "mappings": {
4.      "properties": {
5.        "address": {
6.          "properties": {
7.            "city": {
8.              "type": "text"
9.            },
10.            "number": {
11.              "type": "keyword"
12.            },
13.            "street_name": {
14.              "type": "text"
15.            },
16.            "zipcode": {
17.              "type": "keyword"
18.            }
19.          }
20.        },
21.        "location": {
22.          "type": "geo_point"
23.        }
24.      }
25.    }
26.  }

`![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

我们接下来写入如下的一个文档:



1.  POST myindex/_doc/1
2.  {
3.    "address": {
4.      "zipcode": "17000",
5.      "number": "23",
6.      "city": "Beijing",
7.      "street_name": "wang jing road"
8.    },
9.    "location": {
10.      "lon": 116.478598,
11.      "lat": 39.995007
12.    }
13.  }


从上面的数据中,我们可以看到除了含有 address 信息之前,它还含有一个地理位置的信息 location。在实际的使用中,那个 address 甚至可以是传感器的 id 信息。

如果我们知道 address 信息,那么我们可以通过如下的查询来获得该位置的地理信息:

`

1.  GET myindex/_search?search_type=dfs_query_then_fetch&filter_path=**.hits
2.  {
3.    "size": 1,
4.    "query": {
5.      "bool": {
6.        "should": [
7.          {
8.            "match": {
9.              "address.number": "23"
10.            }
11.          },
12.          {
13.            "match": {
14.              "address.street_name": "wang jing road"
15.            }
16.          },
17.          {
18.            "match": {
19.              "address.city": "Beijing"
20.            }
21.          }
22.        ]
23.      }
24.    }
25.  }

`![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

上面的搜索返回如下的信息:

`

1.  {
2.    "hits": {
3.      "hits": [
4.        {
5.          "_index": "myindex",
6.          "_id": "1",
7.          "_score": 1.4384104,
8.          "_source": {
9.            "address": {
10.              "zipcode": "17000",
11.              "number": "23",
12.              "city": "Beijing",
13.              "street_name": "wang jing road"
14.            },
15.            "location": {
16.              "lon": 116.478598,
17.              "lat": 39.995007
18.            }
19.          }
20.        }
21.      ]
22.    }
23.  }

`![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

很显然,它含有 location 的地理位置信息。

在 Logstash 中使用 Elasticsearch filter 来丰富数据

接下来,我们创建如下的一个 Logstash 配置文件:

logstash.conf

`

1.  input {
2.    http { }
3.  }

5.  filter {
6.    elasticsearch {
7.      query_template => "search-by-name.json"
8.      index => "myindex"
9.      fields => {
10.        "location" => "[location]"
11.        "address" => "[address]"
12.      }
13.      remove_field => ["headers", "host", "@version", "@timestamp"]
14.      ca_file => "/Users/liuxg/elastic/elasticsearch-8.5.2/config/certs/http_ca.crt"
15.      ssl => true
16.      api_key => "Rf-_4IQB-Ec0fhu3PjhI:JlZ0cA8lRQGRDxhWwdDJVg"
17.    }
18.  }

20.  output {
21.    stdout { codec => rubydebug }
22.  }

`![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

如上所示,我们使用 http input 来做测试。在上面,我们使用 elasticsearch filter 来丰富数据。我们希望得到的是 location 及 address。在上面,我们定义 search-by-name.json 如下:

search-by-name.json

`

1.  {
2.    "size": 1,
3.    "query":{
4.      "bool": {
5.        "should": [
6.          {
7.            "match": {
8.              "address.number": "%{[address][number]}"
9.            }
10.          },
11.          {
12.            "match": {
13.              "address.street_name": "%{[address][street_name]}"
14.            }
15.          },
16.          {
17.            "match": {
18.              "address.city": "%{[address][city]}"
19.            }
20.          }
21.        ]
22.      }
23.    }
24.  }

`![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

在上面,我们设置 size 为 1,也即采用最为匹配的那个结果。上面其实就是一个搜索。我们把上述文件置于 Logstash 的安装目录下。另外,我们需要定义证书及 API key。你需要根据自己的配置来对上面的配置进行修改。如果你还不值得如何得到 API key,请阅读我之前的文章 “Logstash:如何连接到带有 HTTPS 访问的集群”。当然如果你的 Elasticsearch 不具有安全配置,那么你就不需要进行任何的配置了。

我们使用如下的命令来进行运行:

 ./bin/logstash -f logstash.conf 

我们接下来在另外一个 terminal 中打入如下的命令:



1.  curl -XPOST "localhost:8080" -H "Content-Type: application/json" -d '{
2.    "test_case": "Address with text",
3.    "name": "Joe Smith",
4.    "address": {
5.      "number": "23",
6.      "street_name": "wang jing road",
7.      "city": "Beijing",
8.      "country": "China"
9.    }
10.  }'


请注意在上面的命令中,它并没有 location 的任何信息。等执行完后,我们可以在 Logstash 的 terminal 中看到如下的输出:

 

如上所示,我们可以看到被丰富的 location 信息。这个信息来源于 Elasticsearch 中的 myindex 索引。

现在你只需要改变输入部分来读取你的数据源,例如从数据库:



1.  jdbc {
2.    jdbc_driver_library => "mysql-connector-java-6.0.6.jar"
3.    jdbc_driver_class => "com.mysql.cj.jdbc.Driver"
4.    jdbc_connection_string => "jdbc:mysql://127.0.0.1:3306/person?useSSL=false"
5.    jdbc_user => "root"
6.    jdbc_password => ""
7.    schedule => "* * * * *"
8.    parameters => { "country" => "France" }
9.    statement => "SELECT p.id, p.name, p.dateOfBirth, p.gender, p.children, a.city, a.country, a.countrycode, a.lat, a.lon, a.zipcode FROM Person p, Address a WHERE a.id = p.address_id AND a.country = :country AND p.id > :sql_last_value"
10.     use_column_value => true
11.     tracking_column => "id"
12.  }


关于这个部分的详细操作请参考文章 “Elasticsearch:将关系数据库中的数据提取到 Elasticsearch 集群中”