kafka教程_使用Storm,Kafka和ElasticSearch处理实时数据–第2部分

kafka教程

kafka教程

这是文章系列的第二部分:使用Storm,Kafka和ElasticSearch处理实时数据。

1.简介

第一部分中,我们描述了问题以及我们将如何解决它。 为了刷新您的记忆,计划是创建一个历史飞行数据的数据缩减系统(您可以从此处免费下载)。 我们将使用以下技术堆栈构建DRS:Apache Storm→Apache Kafka→ElasticSearch→(可视化:Kibana,OpenLayers,OpenMap等)。

我们已经在上一篇文章中解释了ElasticSearch的基础知识及其工作原理。 在本文中,我们将学习如何在ElasticSearch中执行搜索。

2. CRUD命令

您可能熟悉数据库中的首字母缩写CRU D

  • C –创建
  • R –检索或读取
  • U –更新
  • D –删除

下表将每个CRUD命令与其各自的ElasticSearch HTTP / REST命令相对应。 这些命令适用于索引以及文档。

CRUD命令 HTTP / REST命令
创造PUTPOST
GET
更新资料 PUTPOST
删除 DELETE
表1. CRUD和ElasticSearch REST命令

因此,让我们从上一篇文章中学到Kibana,并导航到Kibana的控制台

2.1创建索引

要创建索引flight期,请发出以下命令:

PUT /flight
GET /_cluster/health

请注意,现在群集的运行状况已从绿色更改为黄色。 发生这种情况是因为我们仅运行一个Elasticsearch实例。 单节点群集具有完整的功能,但是无法将数据复制到其他节点以提供弹性。 副本分片必须可用于其他节点,群集状态才能变为绿色。 如果群集状态为红色,则某些数据不可用。

为了解决这个问题,你需要创建ElasticSearch的另一个安装(相同的,但最好到另一台机器),并改变node.nameelasticsearch.yml ; 两个实例中的cluster.name必须保持相同(默认值为elasticsearch )。 另一种方法是在命令行上将配置参数传递给弹性搜索,例如

bin/elasticsearch -Enode.name=node-2 -Epath.data=./node-2/data -Epath.logs=./node-2/logs
GET /_cat/indices?v

health status index  uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   flight w696u4y3SYWuGW--8VzW6Q   1   1          0            0       208b           208b

我们的主分片包含一个副本分片,但未分配给任何节点。

GET /_cat/shards?v

index    shard prirep state      docs   store ip        node
flight       0      p STARTED       0    208b 127.0.0.1 MacBook-Pro.local
flight       0      r UNASSIGNED

您会注意到副本分片未分配( prirep = r表示副本)。

2.2创建文件

让我们向索引添加一些测试数据:

PUT /flight/_doc/1 
{
  "Icao":"A0835D",
  "Alt":2400,
  "Lat":39.984322,
  "Long":-82.925616
}

或作为curl命令:

curl -X PUT "localhost:9200/flight/_doc/1?pretty" -H 'Content-Type: application/json' -d'
{
  "Icao":"A0835D",
  "Alt":2400,
  "Lat":39.984322,
  "Long":-82.925616
}'

Content-Type对于查询成功至关重要。 我们创建了ID = 1的新航班。 我们也可以使用POST代替PUT ,但是,在这种情况下,我们不能传递ID。 在这种情况下,ElasticSearch将为我们的文档生成一个自动ID。 这是ElasticSearch返回的结果:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "flight",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "Icao" : "A0835D",
          "Alt" : 2400,
          "Lat" : 39.984322,
          "Long" : -82.925616
        }
      }
    ]
  }
}

结果文档位于_source键中。

2.3删除文件

如果您知道文档的索引:

DELETE /flight/_doc/1

2.4删除索引

要删除索引,只需发出:

DELETE /flight

2.5导入批量数据

我们的方案是处理航班数据。 理想情况下,这些数据将通过多个传感器(雷达)实时获得,但是由于这很难实现,因此我们将使用可从此处下载的批量飞行历史数据。 有关各个领域的说明,请参见此处

该文件必须以空行结尾。 如果不是,则添加一个。 在下载批处理文件的目录中,发出以下命令(每个.json文件):

curl -H "Content-Type: application/x-ndjson" -XPOST http://localhost:9200/flights/_bulk --data-binary "@2016-07-01-1300Z.json"

请注意,内容类型是"application/x-ndjson"而不是"application/x-json" 。 另外,请注意,我们将数据表示为二进制以便保留换行符。 文件名为2016-07-01-1300Z.json 。 具有相同ID的所有现有文档都将被.json文件中的文档替换。

如果运行此命令,它将失败。 如果可行,那太容易了,不是吗? ElasticSearch预计其.json文件有特定的格式:

{"index":{"_id":4800770}}
{"Rcvr":1,"HasSig":false,"Icao":"494102", "Bad":false,"Reg":"CS-PHB", ...}
...

这意味着您必须将每个下载的.json文件转换为上述格式,包括以下步骤:

  • 在每个实际数据文档上方添加以"index"开头的行
  • "Id":<value >移至{"_id":<value>}

如果您不想花时间手动修改.json文档,那么在下一篇文章中,我们将开发一个Java程序来解析它们,并使用ElasticSearch的REST API将文件插入ElasticSearch中。 到那时,您可以从此处下载只有几个航班的示例.json文件。

2.6搜索查询

ElasticSearch全部与搜索有关。 它允许您使用符合某些条件的搜索查询。

GET /flight/_search?pretty
{ "query": {
     "match_all" : {
     }
   }
}

上面的搜索查询匹配index flight所有文档。 也可以这样简化:

GET /flight/_search

以下查询搜索与给定的Icao匹配的文档。

GET /flight/_search?pretty 
{ "query": {
     "match" : {
	  "Icao" : "A0835D"
     }
   }
}

也可以执行嵌入在请求URL中的搜索:

GET /flight/_search?q=Icao:A0835D

也可以写成:

GET /flight/_search?pretty 
{ "query": {
     "query_string": {
	  "query": "Icao:A0835D"
     }
   }
}

除了"match""query_string"还可以使用"term" 。 使用"term"进行完全匹配(例如布尔值,数字,日期,枚举值,关键字等)。

GET /flight/_search?pretty 
{ "query": {
     "term": {
	  "Mil": true
     }
   }
}

您也可以使用"terms"来搜索值数组。

您可以按"wildcard"进行搜索,并使用通配符*和/或? 或加prefix

GET /flight/_search?pretty 
{ "query": {
     "wildcard": {
	  "Call": "NJ*" 
     }
   }
}

但是请注意,通配符查询可能很慢,特别是如果通配符位于搜索字符串的开头。

您也可以使用 regexp 并为搜索字符串提供正则表达式特殊字符。

或者,您可以使用"ids"搜索文档ID的数组,或者使用"range"提供值的范围(分别对>, ≥, <, ≤使用gtgteltlte )。

GET /flight/_search?pretty 
{ "query": {
     "range": {
	  "Year": {
	    	"gte": "2010",
	    	"lt":  "2016"
        }
     }
   }
}

您还可以使用锚定日期,例如"gte": "2010/01/01||-1y" ,这表示在锚定日期1 2010年1月1日之前的所有日期。可以在此处找到更多信息。

要搜索字段中具有非空值的文档:

GET /flight/_search?pretty 
{ 
   "query": {
     "exists": {
	  "field": "Cou"
     }
   }
}

您也可以使用"match_phrase"来匹配短语,或者使用"multi_match"来匹配许多字段:

GET /flight/_search?pretty 
{ 
   "query": {
     "multi_match": {
        "query": false,
	  "fields": ["Mil", "Gnd"]
     }
   }
}

也可以构建复合查询:

GET /flight/_search?pretty 
{ 
   "query": {
     "bool": {
        "must": [
 		{
		  "match": {
			"Icao": "A0835D"
		  }
		},
 		{
		  "range": {
			"Alt": {
			  "lte": 10000 
			}
		  }
		}
	  ]
     }
   }
}

我们可以像这样改善性能:

GET /flight/_search?pretty 
{ 
   "query": {
     "bool": {
        "must": [
 		{
		  "match": {
			"Icao": "A0835D"
		  }
		}
	  ],
        "filter": [
 		{
		  "range": {
			"Alt": {
			  "lte": 10000 
			}
		  }
		}
	  ]
     }
   }
}

must替代方法是: must_notshould

但是,为什么第二个版本可以提高性能呢? 对象的filter用于匹配或不匹配的查询。 没有关于文件匹配程度的概念。 因此,在这种情况下,对海拔高度≤1000的文档匹配程度进行评分不会增加任何值(当您使用范围时,结果将对查询匹配程度的得分有所帮助)。 此外, filter缓存结果,可以提高后续查询的性能。

2.7更新文件

要更新您知道ID的文档,请使用_update API:

POST /flight/_update/4800770
{
  "doc": {
    "Mil": true
  }
}

使用上述命令,我们也可以向文档中添加新字段。

附带说明一下,ElasticSearch文档是不可变的! 因此,当我们请求更新文档时,ElasticSearch会在后台进行操作,它检索文档,更改其字段并为具有相同ID的文档重新索引,从而有效地替换了它。

可以使用脚本发送更复杂的查询,例如:

POST /flight/_update/4800770
{
  "script": {
    "source": "ctx._source.FlightsCount++"  
  }
}

ctx表示上下文。 还有许多其他更新文档的方法,例如upsert (即根据文档是否已存在有条件地更新或插入文档)。

POST /flight/_update/4800771
{
  "script": {
    "source": "ctx._source.FlightsCount++"  
  },
  "upsert": {
    "Rcvr":1,
    "HasSig":false,
    "Icao":"AE4839",
    ... 
  },
}

由于ID为4800771文档不存在,因此正在使用"upsert" 。 您还可以使用_update_by_query API:

POST /flight/_update_by_query
{
  "script": {
    "source": "ctx._source.FlightsCount++"  
  },
  "query": {
    "match_all": {}
  }
}

请记住,如果上面的查询失败,查询将中止,而不是回滚! 该查询不在事务内运行。 这意味着某些文档可能会更新,而有些则不会。 这就是为什么在运行更新查询之前进行备份很重要的原因。

要替换文档,只需使用与现有文档相同的ID:

PUT /flight/_doc/4800770
{
   "Rcvr":1,
   "HasSig":false,
   "Icao":"494102",
   "Bad":false,
   ...
}

2.8删除文件

还有一个_delete_by_query API:

POST /flight/_delete_by_query
{
  "query": {
    "match_all": {}
  }
}

2.9批量查询

批量API可帮助我们通过一个查询对许多文档执行这些操作。 该API包含4个动作: index,create,update,delete

POST /_bulk
{ "index": { "_index" : "flight", "_id": 10519389 } }
{ "Rcvr":1,"HasSig":true,"Sig":0,"Icao":"A0835D","Bad":false, ... }
{ "create": { "_index" : "flight", "_id": 4800770 } }
{"Rcvr":1,"HasSig":false,"Icao":"494102","Bad":false, ... }
{ "update": { "_index" : "flight", "_id": 4800770 } }
{ "doc": {"Mil": true } }
{ "delete": { "_index" : "flight", "_id": 4800770 } }

索引创建操作之间的区别如下:如果文档已经存在,则创建将引发错误,而索引将替换文档。

如果批量查询要针对相同的索引运行,那么我们可以像这样简化查询:

POST /flight/_bulk
{ "index": { "_id": 10519389 } }
{ "Rcvr":1,"HasSig":true,"Sig":0,"Icao":"A0835D","Bad":false, ... }
{ "create": { "_id": 4800770 } }
{"Rcvr":1,"HasSig":false,"Icao":"494102","Bad":false, ... }
{ "update": { "_id": 4800770 } }
{ "doc": {"Mil": true } }
{ "delete": { "_id": 4800770 } }

失败的操作不会影响其他操作。

3.映射

但是,ElasticSearch如何知道如何映射数据? 动态映射意味着没有明确定义映射,或者至少没有为某些字段定义。 这是通过检查文档字段的值类型来完成的。 如果您对动态映射不满意,则可以进行显式映射。

要查看数据映射,请在Kibana中键入以下内容:

GET /flight/_mapping

ElasticSearch执行日期检测,并检查字段的内容是否与已定义的任何动态数据格式匹配。 默认情况下,这将是年,月和日,中间用斜杠和可选的时间戳分隔。 如果存在匹配项,则匹配日期格式将添加到该字段的映射中。 一个字段可以具有多个映射。 例如, String类型的字段具有两个映射:

  • 作为"type" : "text"
  • "fields"属性,其中包含一个名为"keyword"且类型为"keyword"的字段。

例如

"Call" : {
     "type" : "text",
     "fields" : {
        "keyword" : {
          "type" : "keyword",
          "ignore_above" : 256
        }
     }
},

两者之间的区别在于, "text"类型用于全文搜索,而"keyword"类型用于精确匹配(过滤器),排序,聚合等。

存储在Elasticsearch集群中的每个文档都有一些与之关联的元数据,除了我们在索引文档时指定的数据字段(称为meta-fields)之外

  • _index :包含文档所属索引的名称。
  • _id :存储文档的ID
  • _source :包含在索引文档时传递给Elasticsearch的原始JSON对象。 该字段未编制索引,因此您无法搜索它,但可以检索它。
  • _field_names :包含每个包含非空值的字段的名称。
  • _routing :基于指定值将文档路由到分片的定制路由:文档版本控制:可以存储定制数据

ElasticSearch数据类型可以分为四类:

  • 核心:例如, text ,数字,例如byte (-128至127), shortintegerlongfloathalf_floatscaled_float (存储为longfloat ), doubledatebooleanbinary (使用Base64编码), range (例如{"gte": 1, "lte":10}1-10 )
  • complexobject (JSON), array (展平嵌套的对象), nested (每个对象都被索引为隐藏文档,确保每个对象都是独立的)
  • 地理: geo_pointgeo_shape ( pointpolygonlinestringmultipointmultilinestringmultipolygongeometrycollectionenvelopecircle表示为) GeoJSON对象
  • 专门ipcompletionattachment (需要Ingest附件处理器插件)

您可以通过三种方式提供date

  • 作为string (可以配置日期格式)
  • integer表示从epoch以来的秒数
  • long表示,代表自epoch以来的毫秒数(这是内部存储日期的方式)。

您可以通过以下四种方式之一提供geo_point

  • 作为带有"lat""lon"键的对象
  • 以纬度和经度以逗号分隔的string ,并按此顺序
  • 作为geohash
  • 作为具有经度和纬度值的array

要添加映射:

PUT /flight/_mapping 
{
   "properties": {
     "location": {
       "type": "geo_point"
     }
   }
}

请注意,一旦创建了字段映射,就不能对其进行修改。 唯一的方法是删除并重新创建索引。

在下面的示例中,我们手动创建了各种禁用动态映射的映射。

PUT /flight/_mapping
{
    "dynamic": false,
    "properties": {
      "Rcvr": {
        "type": "integer"
      },
      "Icao": {
        "type": "text"
      },
      ...
      "location": {
        "type": "geo_point"
      }
   }
}

ElasticSearch的映射参数可以帮助创建新的映射。 例如,创建一个自定义location字段,我们可以像这样使用copy_to参数:

PUT /flight/_mapping
{
   "properties": {
      "Lat": {
         "type": "float",
         "copy_to": "location"
      },
      "Long": {
        "type": "float",
        "copy_to": "location"
      },
     "Location": {
       "type": "geo_point"
     }
   }
}

这将是最有可能对你有用的另一种映射参数是format后面的乔达时间格式(默认"strict_date_optional_time||epoch_millis" )。

PUT /flight/_mapping 
{
   properties: {
     "Year": {
       "type": "date",
       "format": "year"
     }
   }
}

如果您有unix时间戳,则可以将其乘以1000。

内置的日期格式可以在这里找到。

您可能会想像这样添加映射:

"FSeen": {
       "type": "date",
       "format": "\/Date(epoch_millis)\/"
     }

映射"Fseen":"\/Date(1467378028852)\/"但是不幸的是,这不会起作用。 我们将在下一篇文章中看到如何处理这种格式。

如果您更新了映射,请在禁用动态映射的情况下发出以下查询以更新ElasticSearch:

POST /flight/_update_by_query?conflicts_proceed

4.总结

在本文中,我们重点介绍了如何使用ElasticSearch作为主要用途,即搜索文档。 在接下来的文章中,我们将学习如何批量导入.json文件ElasticSearch的改造后, .json通过使用JSON库来解析文件到ElasticSearch的大宗原料药想要的格式,而且还.json文件,插入文件ElasticSearch使用其REST API。 然后,您可以重新访问本文并重新运行各种搜索查询以评估结果。

5.参考

  1. Andhavarapu A.(2017年),《学习ElasticSearch》, Packt。
  2. Dixit B.(2016年), ElasticSearch Essentials, Packt。
  3. ElasticSearch教程
  4. Gormley C.&Tong Z.(2015),《 ElasticSearch权威指南》, O'Reilly。
  5. JavaCodeGeeks, ElasticSearch教程,迷你书。
  6. Pranav S.和Sharath KMN(2017),《学习Elastic Stack 6.0》, Packt。
  7. Redko A.(2017年), ElasticSearch教程, JavaCodeGeeks。
  8. 塔瓦A.&Azarmi B.(2019),学习Kibana 7,2版。 Packt。
  9. Wong WT(2019),高级ElasticSearch 7.0 ,Packt。

5.下载命令

那是文章系列的第二部分:使用Storm,Kafka和ElasticSearch处理实时数据。

下载 您可以在此处下载本文提到的命令: 使用Storm,Kafka和ElasticSearch处理实时数据–第2部分

翻译自: https://www.javacodegeeks.com/processing-real-time-data-with-storm-kafka-and-elasticsearch-part-2.html

kafka教程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值