01-正文
本章节下载 (1.62 MB)
目 录
Elasticsearch是一个基于Apache Lucene的搜索和数据分析工具。Elasticsearch使用Lucene作为其核心来实现所有索引和搜索的功能,它通过简单的RESTful API来屏蔽Lucene的复杂性,从而让全文搜索变得简单。
Elasticsearch的特点及优势如下:
· 分布式的实时文件存储,每个字段都被索引并可被搜索。
· 分布式的实时分析搜索引擎。
· 可弹性扩展到上百台服务器规模,处理PB级别结构化或非结构化数据。
· 支持多种分词插件。
图1-1 Elasticsearch组件架构
· Gateway是Elasticsearch用来存储索引的文件系统,支持多种存储类型。
· Gateway的上层是一个分布式的lucene框架。
· Lucene之上是Elasticsearch的模块,包括:索引模块、搜索模块、映射解析模块、数据传输模块等。
· Elasticsearch模块之上是Discovery、Scripting和第三方插件。
¡ Discovery是Elasticsearch的节点发现模块,不同机器上的Elasticsearch节点组成集群需要进行消息通信,集群内部需要选举Master节点,这些工作都是由Discovery模块完成,支持多种发现机制,如Zen、EC2。
¡ Scripting用来支持在查询语句中插入javascript、Python等脚本语言,Scripting模块负责解析这些脚本。
¡ Elasticsearch也支持多种第三方插件。
· 再上层是Elasticsearch的传输模块和JMX。
¡ 传输模块支持多种传输协议,如Thrift、Memecached、Http,默认使用Http。
¡ JMX是java的管理框架,用来管理Elasticsearch应用。
· 最上层是Elasticsearch提供给用户的接口,可以通过RESTful接口和Elasticsearch集群进行交互。
· cluster
代表集群,集群包含多个节点,其中有一个Master节点,Master节点通过选举产生,ES集群中的主从节点是针对集群内部而言的。Elasticsearch的一个概念就是去中心化,字面上理解就是无中心节点,这是对于集群外部而言的,因为从外部来看,Elasticsearch集群在逻辑上是个整体,与集群中任何一个节点通信,其效果都是等价的。
· index
代表索引,用于存储Elasticsearch的数据,类似于关系型数据库的Database。是一个或多个分片分组在一起的逻辑空间。
· shards
代表索引分片,Elasticsearch可以把一个完整的索引分成多个分片,并分布到不同的节点上,构成分布式搜索。分片的数量只能在索引创建前指定,并且索引创建后不能更改。
· replicas
代表索引副本,Elasticsearch可以设置多个索引的副本,副本的作用一是提高系统的容错性,当某个节点某个分片损坏或丢失时可以从副本中恢复。二是提高Elasticsearch的查询效率,Elasticsearch会自动对搜索请求进行负载均衡。
· document
代表文档,Elasticsearch存储的实体,是可以被索引的基本单位,相当于关系型数据库中的行。
· field
代表字段,是组成文档的最小单位。相当于关系型数据中的column。
· mapping
代表类型映射,用来约束字段的类型,可以根据数据自动创建。相当于数据库中的schema。
· recovery
代表数据恢复或数据重新分布,Elasticsearch在有节点加入或退出时会根据机器的负载对索引分片进行重新分配,挂掉的节点重新启动时也会进行数据恢复。
· gateway
代表Elasticsearch索引快照的存储方式,Elasticsearch默认是先把索引存放到内存中,当内存满了时再持久化到本地磁盘。gateway对索引快照进行存储,当这个Elasticsearch集群关闭再重启时就会从gateway中读取索引备份数据。Elasticsearch支持多种类型的gateway,有本地文件系统(默认)、分布式文件系统,如Hadoop的HDFS。
· type
type代表文档类型,类似于关系型数据库中的表,用于区分不同的数据。需要注意的是,在Elasticsearch 7.x版本中,一个索引只能有一个type且默认使用_doc作为索引的type。Elasticsearch官方声明将在Elasticsearch 8版本中彻底移除type。
在新建集群时,选择不同资源模式需要准备不同的资源类型,在Elasticsearch云服务中,Elasticsearch支持部署的资源模式有虚拟机部署和裸金属部署。资源类型准备说明如下:
· 虚拟机集群:新建虚拟机集群前,要求在云操作系统中有可用资源,可通过[资源/计算可用域]完成虚拟机云资源的准备。
· 裸金属集群:裸金属的节点规格根据硬件配置自动获取,规格数据来自云平台的[资源/裸金属资源池]中处于“可分配”状态的节点。
· 运维分析:对IT设备进行运维分析与故障定位、对业务指标分析运营效果。
· 统计分析:20余种统计分析方法、近10种划分维度。
· 实时高效:从入库到能够被检索到,时间差在数秒到数分钟之间。
· 实时检索:站内资料或商品信息更新数秒至数分钟即可被检索。
· 分类统计:检索同时可以将符合条件的商品进行分类统计。
· 高亮显示:提供高亮能力,页面可自定义高亮显示方式。
新建集群前,要求在云平台中已完成云资源的准备。
根据集群部署规划,在云资源准备完成以后,可新建Elasticsearch集群。新建Elasticsearch集群的步骤详情可参见产品安装部署手册或在线联机帮助。
本文档内容将以集群已创建成功为前提,介绍如何进行状态检查、以及对集群的基本操作等。
· 关于Elasticsearch的部署流程以及部署过程中相关的参数说明等,详情请参见产品安装部署手册。
· Elasticsearch搭建模式包括单节点和集群模式,其中集群模式中至少需要3个节点。
Elasticsearch集群创建成功后可以通过界面上的集群状态检查,确保创建的集群可用。可在集群管理页面查看集群列表中的运行状态,若运行状态为“运行中”、健康状态为“健康”,则表示集群运行正常;否则,集群可能处于异常状态,需排查相应问题。如图2-1所示。
进入Elasticsearch集群详情页面,如图2-2所示。详情页面主要展示基本信息、概览、组件、主机、索引、告警和计费等相关信息。
主要功能如下:
· 基本信息:展示该集群的基本信息,包含集群模式、节点数、资源区域、资源类型、密钥对、运行状态、监控状态等。
· 概览:展示了该集群中组件的统计、CPU\磁盘\内存使用率的性能趋势、CPU\磁盘\内存使用率等。
· 组件:展示集群中安装的组件以及对组件的停止、重启等操作;单击组件名,可查看组件中进程的部署拓扑、配置、配置修改历史信息。
· 主机:展示集群中的主机信息,可以执行主机扩容、查看监控详情等操作。单击主机名可跳转至主机详情页面。
· 索引:展示集群的索引列表;可在该页面新建、关闭和删除索引操作。
· 告警:展示告警信息统计数,以及产生的告警信息,可进行告警相关操作。
· 计费:展示当前集群计费信息,包括计费开始/结束时间、产生的费用。
Elasticsearch集群搭建好之后,可以通过调用curl命令进行测试,默认情况下,Elasticsearch的监听端口是9200。
在Linux环境中,基于curl命令,向Elasticsearch集群中的任意节点发送请求,命令如下:
curl –X GET -u elastic:<password> http://<Elasticsearch_ip>:9200
其中:
· Elasticsearch_ip表示安装Elasticsearch节点的服务器IP地址。
· password指新建集群时指定的管理用户elastic的密码。
得到的返回结果示例:
{
"name" : "test00.hde.com",
"cluster_name" : "my_es_cluster",
"cluster_uuid" : "YUCbB_1VTS6fmvPUfIDnUA",
"version" : {
"number" : "7.4.0",
"build_flavor" : "default",
"build_type" : "rpm",
"build_hash" : "22e1767283e61a198cb4db791ea66e3f11ab9910",
"build_date" : "2019-09-27T08:36:48.569419Z",
"build_snapshot" : false,
"lucene_version" : "8.2.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
通过Linux环境下的curl命令访问Elasticsearch的9200端口进行添加文档。
示例:
curl -H "Content-Type:application/json" -X POST -u elastic:<password> http://<Elasticsearch_ip>:9200/test_index/test_type?pretty -d '{"name": "xiaoming", "age": 15}'
其中:
· test_index:是索引名称,如果集群中不存在该索引则会自动创建。
· 每个文档都有自己的ID和type,在返回结果中会显示,如果在创建时没有指定,则系统会为其随机生成一个。本例中指定了type为test_type,没有指定ID。
创建成功响应示例:
{
"_index" : "test_index",
"_type" : "test_type",
"_id" : "LbXSC3IBzPEntZG0Oj8i",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
若Elasticsearch中存在文档,可以使用如下命令更新文档。
curl -u elastic:<password> http://<Elasticsearch_ip>:9200/test_index/test_type/<doc_id>
其中:
· doc_id:表示文档ID。
示例:
curl -H "Content-Type:application/json" -X POST http://<Elasticsearch_ip>:9200/test_index/test_type/LbXSC3IBzPEntZG0Oj8i?pretty -d '{"name": "xiaoming", "age": 17}'
更新成功响应示例如下:
{
"_index" : "test_index",
"_type" : "test_type",
"_id" : "LbXSC3IBzPEntZG0Oj8i",
"_version" : 2,
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1
}
可以通过GET命令对文档进行检索查询。
示例:
curl -H "Content-Type:application/json" -X GET -u elastic:<password> http://<Elasticsearch_ip>:9200/test_index/test_type/AWiyyYenTVhrxfir_T01?pretty
检索结果如下:
{
"_index" : "test_index",
"_type" : "test_type",
"_id" : "AWiyyYenTVhrxfir_T01",
"_version" : 2,
"_seq_no" : 1,
"_primary_term" : 1,
"found" : true,
"_source" : {
"name" : "xiaoming",
"age" : 17
}
}
可以通过GET或POST命令指定索引、类型或URL等参数对文档进行搜索。示例如下:
· 搜索集群中的所有文档
curl -H "Content-Type:application/json" -X GET -u elastic:<password> http://<Elasticsearch_ip>:9200/_search
· 搜索指定索引下面的所有文档
curl -H "Content-Type:application/json" -X GET -u elastic:<password> http://<Elasticsearch_ip>:9200/<index_name>/_search
· 搜索索引中指定类型的所有文档
curl -H "Content-Type:application/json" -X GET -u elastic:<password> http://<Elasticsearch_ip>:9200/<index_name>/<type_name>/_search
以上示例中的部分参数解释如下:
· <Elasticsearch_ip>:表示安装Elasticsearch节点的服务器IP地址。
· password:指新建集群时指定的管理用户elastic的密码。
· index_name:索引名称。
· type_name:类型名称。
curl -H "Content-Type:application/json" -XDELETE -u elastic:<password> http://<Elasticsearch_ip>:9200/<index_name>/<index_type>/<id>
其中:
· Elasticsearch_ip:表示安装Elasticsearch节点的服务器IP地址。
· password:指新建集群时指定的管理用户elastic的密码。
· index_name:索引名称。
· index_type:类型名称。
· id:文档ID。
curl -H "Content-Type:application/json" -XDELETE -u elastic:<password> http://<Elasticsearch_ip>:9200/<index_name>
其中:
· Elasticsearch_ip:表示安装Elasticsearch节点的服务器IP地址。
· password:指新建集群时指定的管理用户elastic的密码。
· index_name:索引名称。
Elasticsearch 5.X之后的字段类型不再支持string,由text或keyword取代。如果仍使用string,会给出警告。
· 当一个字段需要被全文搜索,比如Email内容、产品描述,应该使用text类型。设置text类型以后,字段内容会被分析,在生成倒排索引以前,字符串会被分析器分成一个一个词项。
· text类型的字段不用于排序,较少用于聚合场景(termsAggregation除外)。
· keyword类型不会进行分词,适用于索引结构化的字段,比如Email地址、主机名、状态码和标签。如果字段需要进行过滤(比如查找已发布博客中status属性为published的文章)、排序、聚合等操作可以使用该类型。
· Elasticsearch集群扩容是指集群新添加节点并在该节点上新增Elasticsearch服务。
· 主机扩容只能选择与原集群节点相同的规格。
· 主机扩容操作不可中止或暂停;集群中的主机不可删除。
Elasticsearch扩容操作步骤如下:
(1) 在云服务Elasticsearch管理页面的左侧导航树中选择[集群管理],进入集群管理页面。
(2) 选择[集群列表]页签,单击集群名称可跳转至集群详情页面。
(3) 选择[主机]页签,单击<主机扩容>按钮,弹出主机扩容页面;或单击右上角<集群操作/主机扩容>进入主机扩容页面。
(4) 选择扩容节点数,单击<确定>按钮,即完成主机扩容。
图3-1 Elasticsearch集群扩容
通过顶部导航栏[云服务/分析搜索引擎Elasticsearch]进入Elasticsearch后,在左侧导航树[主机管理]及[磁盘管理]进入对应页面,可以查看创建的所有Elasticsearch集群主机,以及主机的资源使用情况和磁盘使用情况。
图3-2 主机管理
图3-3 磁盘管理
Elasticsearch云服务对Elasticsearch集群提供监控告警的功能。通过顶部导航栏[云服务/分析搜索引擎Elasticsearch]进入Elasticsearch后,选择左侧导航树[告警管理]进入告警管理页面,可以查看告警信息,并对告警联系人及告警联系组进行管理。
图3-4 告警列表
图3-5 告警联系人管理
日志管理主要是对Elasticsearch服务运行日志及集群运行日志的收集并下载供用户使用的,提高快速定位异常问题的效率。在[日志管理]页面可收集运行日志、集群日志。本节仅支持系统管理员操作。
运行日志以天为单位进行收集和下载,当某天没有产生日志信息时,下载成功后解压没有该天的日志文件信息。
在服务运行过程中,若遇到异常或其他情况,可查看运行日志信息以便定位异常。
(1) 在日志管理页面,选择<运行日志收集>,弹出运行日志收集窗口。
(2) 输入SSH端口信息和root密码后,单击<测试远程连接>按钮,返回远程连接校验结果。
(3) 显示运行日志收集条件。部分参数说明如下:
¡ 远程连接信息
- SSH端口:云平台远程SSH连接端口。
- root密码:root用户的远程登录密码。
¡ 日志收集类型
- 基础日志:base服务中的相关日志,默认选中不可修改。
- 服务日志:Elasticsearch服务运行的日志,默认选中不可修改。
¡ 日志收集时间:日志产生的时间范围,默认选择前一天和当天的时间,最大范围30天。
(4) 相关信息配置完成后,单击<确定>按钮,即可开始运行日志收集并下载日志压缩文件。
仅支持下载集群节点为“在线”状态的集群日志信息。
集群使用过程中,若出现集群运行异常或其他情况,可查看集群节点的日志信息以便定位异常。
(1) 在日志管理页面,选择<集群日志收集>,弹出集群日志收集窗口。
(2) 选择需要下载日志信息的集群名称,会查询当前集群下的节点信息,并展示在下方列表中,部分参数说明如下:
¡ 节点名:集群节点的名称。
¡ 状态:集群节点的状态,分为在线、离线两种状态。
¡ 节点IP:集群节点的IP信息。
(3) 当集群节点状态为“在线”时,单击列表操作列的<下载>按钮,即可开始集群日志收集并下载日志压缩文件。
本平台Elasticsearch云服务对接开源Kibana产品,可通过Elasticsearch云服务跳转至Kibana页面进行更多Elasticsearch管理操作。
Kibana提供丰富的Elasticsearch管理功能,更多使用信息可以访问:https://www.elastic.co/guide/en/kibana/7.6/index.html
在[集群管理/集群列表]页面,单击操作列的<Kibana>按钮,即可进入Kibana管理页面。
图3-6 Kibana首页
(1) 单击左侧导航树中的<Management>按钮进入管理界面。
(2) 单击左上方<Index Management>查看索引数据。
图3-7 Index Management管理页面
(3) 勾选一个索引,单击<Manage index>出现下拉列表,可对当前索引进行关闭、删除、清理缓存等各种操作。
图3-8 Kibana索引管理
(1) 单击左侧导航树中的<Dev Tool>按钮进入Console界面。
(2) 在输入区域输入命令,直接访问Elasticsearch的Restful接口。(不用输入Elasticsearch主机地址和认证信息。)
本节只介绍部分API的使用,详细的API使用方式请参考Elasticsearch官网:https://www.elastic.co/guide/en/elasticsearch/reference/7.4/rest-apis.html。
· 通过该API可以获取一个集群健康的简要状态。例如下面的API可以获取集群健康状态、节点数、分片数据及副本数等信息。
curl -H 'Content-type:application/json'-XGET 'localhost:9200/_cluster/health?pretty'
响应如下:
{
"cluster_name" : "testcluster",
"status" : "yellow",
"timed_out" : false,
"number_of_nodes" : 1,
"number_of_data_nodes" : 1,
"active_primary_shards" : 5,
"active_shards" : 5,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 5,
"delayed_unassigned_shards": 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch": 0,
"task_max_waiting_in_queue_millis": 0,
"active_shards_percent_as_number": 50.0
}
· 该API也可以针对一个或多个索引执行请求以获得指定索引的健康状态:
curl -XGET 'localhost:9200/_cluster/health/test1,test2?pretty'
集群健康的状态是:green、yellow或red。从分片的角度来说:
¡ red表示索引存在不能够提供正常服务的主分片。
¡ yellow表示索引的主分片正常,但是存在不能够提供正常服务的副本分片。
¡ green表示索引完全正常,主分片和副本分片均正常。
索引的状态由最差的分片状态决定。集群状态由最差的索引状态所决定。
· 该API规定了一个超时阈值,在达到这个阈值之前如果集群达到了某个标记的健康级别就返回。例如,为了集群达到yellow级别下面将等待50秒(如果在50秒之前达到了green或yellow状态,它将在这时候返回):
curl -H "Content-type:application/json" -XGET 'localhost:9200/_cluster/health?wait_for_status=yellow&timeout=50s&pretty'
通过该API可以获取一个集群更全面的状态(包含Elasticsearch集群节点信息、集群级别的设置、集群中索引信息以及分片的位置信息等)。
curl -H "Content-type:application/json" -XGET 'http://localhost:9200/_cluster/state?pretty'
默认情况下,该集群状态的请求被路由到Master(主)节点,确保返回最新的集群状态信息。
该API可以通过reroute命令对路由进行重新分配。例如,可以将一个分片使用“move”关键字从一个节点明确的移动到另一个节点。
下面是一个简单的重新路由API调用的例子(例子中索引名称是route-test)。
(1) 查看索引中分片的详细信息:
curl -H 'Content-Type:application/json' -XGET http://101.66.62.160:9200/_cat/shards/route-test?v
返回信息如下:
index shard prirep state docs store ip node
route-test 0 p STARTED 0 230b 101.66.62.160 test160.hde.com
从返回信息中可以看到该索引有一个分片,位于节点test160.hde.com上,分片号是0。
(2) 获取Elasticsearch集群中的节点信息,获知集群中每一个节点的名字。
curl -H 'Content-Type:application/json' -XGET http://101.66.62.160:9200/_cat/nodes?v
返回信息如下:
ip heap.Percent ram.percent cpu load_1m load_5m load_15m node.role master name
101.66.62.161 34 63 1 0.68 0.67 0.64 dim - test161.hde.com
101.66.62.162 31 58 1 0.62 0.74 0.85 dim * test162.hde.com
101.66.62.160 20 76 2 0.76 0.79 1.05 dim - test160.hde.com
(3) 进行重新路由,将route-test中的分片0从test160.hde.com节点重新路由到节点test161.hde.com上。
curl -H 'Content-Type:application/json' -XPOST http://101.66.62.160:9200/_cluster/reroute?pretty -d
'{
"commands":[{
"move":{
"index":"route-test",
"shard":0,
"from_node":"test160.hde.com",
"to_node":"test161.hde.com"
}
}]
}'
通过该API可以获取集群范围内的统计信息。该API返回基本的索引metric(分片数量、存储大小、内存使用)和关于当前集群(节点的编号、角色、系统等信息)中节点的信息。
curl -XGET 'http://localhost:9200/_cluster/stats?human&pretty'
通过该API可以更新集群范围中指定的配置。更新的配置既可以是永久的(需要重启集群),也可以是瞬时的(不需要重启集群)。示例:
curl -H "Content-type:application/json" -XPUT localhost:9200/_cluster/settings -d
'{
"persistent":{
"discovery.zen.minimum_master_nodes":2
}
}'
或者:
curl -H "Content-type:application/json" -XPUT localhost:9200/_cluster/settings -d '{
"transient" : {
"discovery.zen.minimum_master_nodes" : 2
}
}'
通过该API可以获取集群中一个或多个节点的信息。
· 获取集群中所有节点的概要信息
curl -XGET 'http://localhost:9200/_cat/nodes?v'
· 获取集群中所有节点的详细信息
curl -XGET 'http://localhost:9200/_nodes?pretty'
· 获取了nodeId1和nodeId2的节点的统计信息
curl -XGET 'http://localhost:9200/_nodes/nodeId1,nodeId2'
创建索引(index API)允许实例化一个索引。Elasticsearch支持多种索引操作,包括跨多个索引执行操作。
· 索引设置
每个索引创建的时候可以包含与之关联的特定设置。
curl -H "Content-type:application/json" -XPUT 'localhost:9200/weibo?pretty' -d'
{
"settings": {
"index": {
"number_of_shards" : 3,
"number_of_replicas" : 2
}
}
}'
上述curl 命令创建了一个weibo索引,包含3个分片,2个副本。默认number_of_shards为5,默认number_of_replicas为1(对于主shard只有一个副本)。
命令可简化为:
curl -H "Content-type:application/json" –XPUT localhost:9200/weibo?pretty -d'
{
"settings" : {
"number_of_shards" :3,
"number_of_replicas" :2
}
}'
· Mappings/映射
在Elasticsearch 7.4中,创建映射时无需再指定type,否则会报错。创建索引允许提供包含一个或多个映射的设置:
curl -H "Content-type:application/json" -XPUT 'localhost:9200/test?pretty' -d'
{
"settings" : {
"number_of_shards" : 1
},
"mappings" : {
"properties" : {
"field1" : { "type" : "text" }
}
}
}'
· Aliases/别名
创建索引可以设置其别名:
curl -H "Content-type:application/json" -XPUT 'localhost:9200/test?pretty' -d'
{
"aliases" : {
"alias_1" : {},
"alias_2" : {
"filter" : {
"term" : {"user" : "kimchy" }
},
"routing" : "kimchy"
}
}
}'
上面的示例是在创建test索引的同时制定了两个别名alias_1和alias_2。其中alias_2给该别名指定了过滤操作,所有使用该别名的操作都是在对test索引进行filter过滤之后的结果集上进行的。
获取索引信息API可以获得一个或多个索引的信息,API必须指定一个索引、别名或通配符表达式。例如获得weibo索引的信息,命令如下:
curl -XGET 'localhost:9200/weibo?pretty'
还可以通过在URL后指定一个逗号分隔的列表来对返回的信息进行筛选,例如返回weibo的设置和映射:
curl -XGET 'localhost:9200/weibo/_settings?pretty'
curl -XGET 'localhost:9200/weibo/_mappings?pretty'
删除索引API可以用来删除集群中的索引,删除必须指定索引、别名或通配符表达式,例如删除weibo索引,命令如下:
curl -H "Content-Type:application/json" -XDELETE 'localhost:9200/weibo?pretty'
删除索引API也可以应用于多个索引,通过使用逗号分隔。或者通过_all或者*,来删除所有index。
为了安全起见,可以通过设置action.destructive_requires_name为true来避免通配符或者_all进行删除所有索引操作,这个设置也可以通过集群API设置。
该API用来检查index(indics)是否存在。例如:
curl -H "Content-Type:application/json" -X GET 'localhost:9200/weibo?pretty'
HTTP状态码表示index存在与否。如果不存在提示404,如果存在,将返回索引信息。
提交映射允许提交自定义的类型映射至一个新的索引,或者往已存在的索引中新加一个字段。
· 创建一个名叫weibo的索引,包含一个字段message。
curl -H "Content-type:application/json" -XPUT 'localhost:9200/weibo?pretty' -d'
{
"mappings": {
"properties": {
"message": {
"type":"text"
}
}
}
}'
· 使用PUT mapping API增加一个字段。
curl -H "Content-type:application/json" -XPUT 'localhost:9200/weibo/_mapping?pretty' -d'
{
"properties": {
"name": {
"type": "text"
}
}
}'
获取映射API允许获取索引或索引类型的映射定义。
curl -H "Content-type:application/json" -XGET 'localhost:9200/weibo/_mapping?pretty'
获取字段映射API允许检索一个或多个字段的映射定义。
· 仅返回字段文本的映射。
curl -XGET 'localhost:9200/weibo/_mapping/field/message?pretty'
· 返回多个字段(如获取message、date字段)的映射定义。
curl -XGET 'localhost:9200/weibo/_mapping/field/message,date?pretty'
索引级统计信息API提供索引上发生不同操作的统计信息。API 提供了索引级范围的统计信息(虽然大多数统计信息可以使用节点级别范围检索)。
可以使用以下命令,返回所有索引的高聚合和索引等级的统计信息请求:
curl -X GET 'localhost:9200/_stats?pretty'
可以使用以下方式检索特定索引的统计信息:
curl -X GET 'localhost:9200/index1,index2/_stats?pretty'
默认情况下,返回所有统计信息。可以通过指定URL返回特定的统计信息。这些统计信息可以是表4-1中的任意一种。
字段 |
说明 |
docs |
文档和已删除文档(尚未合并的文档)的数量 注意,此值受刷新索引的影响 |
store |
索引的大小 |
indexing |
索引统计信息,可以用逗号分隔的type列表组合,以提供文档级统计信息 |
Get |
获取统计信息,包括缺失的统计信息 |
search |
包含建议统计信息的搜索统计信息。可以通过添加额外group参数(搜索操作可以与一个或多个group相关联)来包含自定义组的统计信息。groups参数接受以逗号分隔的group名称列表。使用_all返回所有组的统计信息 |
segments |
检索打开的分段的内存使用。可以选择设置include_segment_file_sizes标志,报告每个Lucene索引文件的聚合磁盘使用情况 |
completion |
完成建议统计 |
fielddata |
正排索引统计信息 |
flush |
刷新统计信息 |
merge |
合并统计信息 |
request_cache |
Shard request cache statistics |
refresh |
刷新统计信息 |
warmer |
Warmer statistics |
translog |
事务日志统计信息 |
清理缓存API可清除与一个或多个索引相关联的所有缓存和特定缓存。
curl -H "Content-Type:application/json" -XPOST 'localhost:9200/weibo/_cache/clear?pretty'
默认情况下,API会清除所有缓存。可以通过设置query、fielddata或者request来显式清除特定高速缓存。
与特定字段相关的所有高速缓存也可以通过使用逗号分隔符的相关字段列表指定fields参数来清除。
清除缓存API可以通过单个调用应用于多个索引,甚至可以应用于_all索引。
curl -H "Content-Type:application/json" -XPOST 'localhost:9200/index1,index2/_cache/clear?pretty'
刷新API允许通过API刷新一个或多个索引。索引的刷新过程基本上通过将数据刷新到索引存储、清除内部事务日志来释放索引的内存。默认情况下,Elasticsearch使用内存触发的方式,以便根据需要自动触发刷新操作,以清理内存。
curl -H "Content-Type:application/json" -XPOST 'localhost:9200/weibo/_flush?wait_if_ongoing=true&force=true'
表4-2 请求参数列表
字段 |
说明 |
wait_if_ongoing |
设置为true,如果另一个刷新操作正在执行,则当前刷新操作将阻塞,只到刷新可以被执行。默认值为false,如果另一个flush操作正在执行,将会导致抛出分片级别的异常 |
force |
强制刷新缓存中的内容到磁盘 |
刷新API可以通过一次调用应用于一个或多个索引,甚至应用于_all索引。
curl -H "Content-Type:application/json" -XPOST 'localhost:9200/index1,index2/_flush?pretty'
该API允许用户显式地刷新一个或多个索引,同时默认情况下,Elasticsearch内部也会周期性地调用该API对索引进行刷新,从而使得上次刷新操作与本次刷新操作期间对索引的更新能够被搜索到。
curl -H "Content-Type:application/json" -XPOST 'localhost:9200/weibo/_refresh?pretty'
重新加载API可以通过单个调用应用于多个索引,甚至可以应用在_all索引上。
curl -H "Content-Type:application/json" -XPOST 'localhost:9200/index1,index2/_refresh?pretty'
文档是Elasticsearch中索引的主要实体,文档由字段构成。程序中大多的实体或对象能够被序列化为包含键值对的JSON对象,键(key)是字段(field)或属性(property)的名字,值(value)可以是字符串、数字、布尔类型、另一个对象、值数组或者其他特殊类型,比如表示日期的字符串或者表示地理位置的对象。以下是一个常见的文档:
{
"name": "John Smith",
"age": 42,
"confirmed": true,
"join_date": "2014-06-01",
"home": {
"lat": 51.5,
"lon": 0.1
},
"accounts": [
{
"type": "facebook",
"id": "johnsmith"
},
{
"type": "weibo",
"id": "johnsmith"
}
]
}
通常认为对象(object)和文档(document)是等价相通的。不过两者之间还存在差别:
· 对象(Object)是一个JSON结构体(类似于哈希、hashmap、字典或者关联数组);对象(object)中还可能包含其他对象(object)。
· 在Elasticsearch中,文档(document)这个术语有着特殊含义。它特指最顶层结构或者根对象(root object)序列化成的JSON数据(以唯一ID标识并存储于Elasticsearch中)。
表4-3 文档元数据
节点 |
说明 |
_index |
文档存储的地方 |
_type |
文档代表的对象的类 |
_id |
文档的唯一标识 |
文档通过index API被索引,使数据可以被存储和搜索。文档通过其_index、_type、_id唯一确定。可以手动指定一个_id或者使用默认生成的。
· 手动指定ID
如果文档有自然的标识符(例如user_account字段或者其他值表示文档),就可以指定_id,使用以下形式的index API:
curl -H "Content-Type:application/json" -XPUT 'localhost:9200/<index>/<type>/<id>?pretty'
{
"field": "value",
...
}
例如索引名称为“website”,类型为“blog”,手动指定的ID为“123”,索引请求如下:
curl -H "Content-Type:application/json" -XPUT 'localhost:9200/weibo/blog/123?pretty' –d'
{
"title": "My first blog entry",
"text": "Just trying this out...",
"date": "2020/01/01"
}'
Elasticsearch的返回值:
{
"_index": "website",
"_type": "blog",
"_id": "123",
"_version": 1,
"created": true
}
响应表明请求的索引已经被成功创建,这个索引中包含_index、_type和_id元数据,以及一个新元素:_version。
Elasticsearch中每个文档都有版本号,每当文档变化(包括删除),Version都会增加。
· 自增ID
如果数据没有指定的ID,Elasticsearch可以自动生成。
URL现在只包含_index和_type两个字段:
curl -H "Content-Type:application/json" -XPUT 'localhost:9200/weibo/blog?pretty' -d'
{
"title": "My second blog entry",
"text": "Still trying this out...",
"date": "2020/01/01"
}'
响应内容与刚才类似,只有_id字段变成了自动生成的值:
{
"_index": "website",
"_type": "blog",
"_id": "AVaC8E_4YMSUVyM3lXBQ",
"_version": 1,
"created": true
}
自动生成的ID有22个字符长,是基于URL-safe Base64编码的全局唯一的标识符。
请求方式如下:
curl -i -XHEAD http://localhost:9200/website/blog/123
响应结果如下:
· 如果文档存在,Elasticsearch将会返回200 OK状态:
HTTP/1.1 200 OK
Warning: 299 Elasticsearch-7.4.0-22e1767283e61a198cb4db791ea66e3f11ab9910 "[types removal] Specifying types in document get requests is deprecated, use the /{index}/_doc/{id} endpoint instead."
Content-Type: text/plain; charset=UTF-8
Content-Length: 200
· 如果不存在返回404 Not Found:
HTTP/1.1 404 Not Found
Warning: 299 Elasticsearch-7.4.0-22e1767283e61a198cb4db791ea66e3f11ab9910 "[types removal] Specifying types in document get requests is deprecated, use the /{index}/_doc/{id} endpoint instead."
Content-Type: text/plain; charset=UTF-8
Content-Length: 89
· 已索引的文档在Elasticsearch中是不可变的,不能修改。如果需要更新已存在的文档,可使用index API重建索引(reindex)或者替换掉它。
curl -H "Content-Type:application/json" -XPUT 'localhost:9200/weibo/blog/123?pretty'
{
"title": "My first blog entry",
"text": "I am starting to get the hang of this...",
"date": "2020/01/02"
}
在返回结果中,我们可以看到Elasticsearch把_version增加了。
{
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 2,
"created": false
}
created标识为false,表示该索引已经存在相同ID的文档。
· Elasticsearch已经标记旧文档为删除,并添加了一个完整的新文档。旧版本文档不会立即消失,但也不能被访问。Elasticsearch会在后续操作自动清理被标记删除的文档。
Update API修改文档的局部过程如下:
a. 从旧文档中检索JSON
b. 修改
c. 删除旧文档
d. 索引新文档
唯一的不同是Update API完成这一过程只需要一个客户端请求即可,不再需要get和index请求。
当索引一个新文档,_index、_type、_id三者唯一确定一个文档。所以要想保证文档是新加入的,最简单的方式是使用POST方法让Elasticsearch自动生成唯一_id:
curl -H "Content-Type:application/json" -XPUT 'localhost:9200/weibo/blog?pretty'
{ ... }
然而,如果想使用自定义的_id,我们必须告诉Elasticsearch应该在_index、_type、_id三者都不同时才接受请求。为了做到这点有两种方法:
· 第一种方法使用op_type查询参数,如果索引中不存在该文档则添加成功,否则添加文档失败,并返回失败原因,索引中已经存在对应文档
curl -H "Content-Type:application/json" -XPUT 'localhost:9200/weibo/blog/123?op_type=create'
{ ... }
· 第二种方法是在URL后加/_create做为端点:
curl -H "Content-Type:application/json" -XPUT 'localhost:9200/weibo/blog/123/_create'
{ ... }
如果请求成功的创建了一个新文档,Elasticsearch将返回正常的元数据且响应状态码是201 Created。
如果包含相同的_index、_type和_id的文档已经存在,Elasticsearch将返回409 Conflict响应状态码,错误信息类似如下:
{
"error" : "DocumentAlreadyExistsException[[website][4] [blog][123]:
document already exists]",
"status" : 409
}
删除文档的语法模式与之前基本一致,需要使用DELETE方法:
curl -X DELETE localhost:9200/website/blog/123?pretty
如果文档被找到,Elasticsearch将返回deleted。
{
"_index" : "weibo",
"_type" : "_doc",
"_id" : "123",
"_version" : 2,
"result" : "deleted"
}
如果文档未找到,我们将得到一个Not Found响应,响应体是这样的:
{
"_index" : "weibo",
"_type" : "_doc",
"_id" : "1111",
"_version" : 1,
"result" : "not_found"
}
即使文档不存在字段"found"的值是false,字段_version依旧增加1。这是内部记录的一部分,可以保证多节点间数据操作的一致性。
使用update API请求来实现局部更新,例如增加数量的操作。Update API必须遵循文档是不可变的,不能被更改,只能被替换的规则。Update API处理的流程是:检索-修改-重建索引,这样可以减少其他进程可能导致冲突的修改。
最简单的update请求表单接受一个局部文档参数doc,它会合并到现有文档中-对象合并在一起,存在的标量字段被覆盖,新字段被添加。
例如,使用以下请求为博客添加一个tags字段和一个views字段:
curl -H "Content-Type:application/json" -XPOST localhost:9200/website/blog/1/_update?pretty
{
"doc" : {
"tags" : [ "tESting" ],
"views": 0
}
}
请求成功,我们将看到如下响应结果:
{
"_index" : "website",
"_id" : "1",
"_type" : "blog",
"_version" : 3
}
检索文档显示被更新的_source字段:
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_version": 3,
"found": true,
"_source": {
"title": "My first blog entry",
"text": "Starting to get the hang of this...",
"tags": [ "tESting" ],
"views": 0
}
}
新添加的字段已经被添加到_source字段中。
合并多个请求可以避免每个请求单独的网络开销。批量检索文档,可以使用multi-get或者mget API。
Mget API参数是一个docs数组,数组的每个节点定义一个文档的_index、_type、_id元数据。在检索一个或几个确定的字段,也可以定义一个_source参数:
curl -H "Content-Type:application/json" -XPOST localhost:9200/_mget?pretty
{
"docs" : [
{
"_index" : "website",
"_type" : "blog",
"_id" : 2
},
{
"_index" : "website",
"_type" : "blog",
"_id" : 1,
"_source": "views"
}
]
}
响应体也包含一个docs数组,每个文档还包含一个响应,它们按照请求定义的顺序排列。每个这样的响应与单独使用get request响应体相同:
{
"docs" : [
{
"_index" : "website",
"_id" : "2",
"_type" : "blog",
"found" : true,
"_source" : {
"text" : "This is a piece of cake...",
"title" : "My first external blog entry"
},
"_version" : 10
},
{
"_index" : "website",
"_id" : "1",
"_type" : "blog",
"found" : true,
"_version" : 2,
"_source" : {
"views" : 2
}
}
]
}
如果检索的文档在同一个_index中(甚至在同一个_type中),可以在URL中定义一个默认的/_index或者/_index/_type。
在单独的请求中使用这些值:
curl -H "Content-Type:application/json" -XPOST localhost:9200/website/blog/_mget?pretty
{
"docs" : [
{ "_id" : 2 },
{ "_type" : "blog", "_id" : 1 }
]
}
事实上,如果所有文档具有相同_index和_type,也可以通过简单的ids数组来代替完整的docs数组:
curl -H "Content-Type:application/json" -XPOST localhost:9200/website/blog/_mget?pretty
{
"ids" : [ "2", "1" ]
}
注意到我们请求的第二个文档并不存在。我们定义了类型为blog,但是ID为1的文档类型为blog。这个不存在的文档会在响应体中被告知。
{
"docs" : [
{
"_index" : "website",
"_type" : "blog",
"_id" : "2",
"_version" : 10,
"found" : true,
"_source" : {
"title": "My first external blog entry",
"text": "This is a piece of cake..."
}
},
{
"_index" : "website",
"_type" : "blog",
"_id" : "1",
"found" : false
}
]
}
事实上第二个文档不存在并不影响第一个文档的检索,每个文档的检索和报告都是独立的。
就像mget允许一次性检索多个文档一样,bulk API允许使用单一请求来实现多个文档的create、index、update或delete。这对索引类似于日志这样的数据流非常有用,它们可以以成百上千的数据为一个批次按序进行索引。
bulk请求体如下:
{ action: { metadata }}\n
{ request body }\n
{ action: { metadata }}\n
{ request body }\n
...
这种格式类似于用"\n"符号连接起来的一行一行的JSON文档流(stream)。两个重要的点需要注意:
· 每行必须以"\n"符号结尾,包括最后一行。这些都是作为每行有效的分离而做的标记。
· 每一行的数据不能包含未被转义的换行符,会干扰分析,这意味着JSON不能被格式化输出。
action/metadata这一行定义了文档行为(what action)发生在哪个文档(which document)。行为(action)必须是表4-4中几种行为之一:
行为 |
说明 |
create |
创建文档 |
index |
创建新文档或替换已有文档 |
update |
局部更新文档 |
delete |
删除一个文档 |
在索引、创建、更新或删除时必须指定文档的_index、_type、_id这些元数据(metadata)。
例如删除请求格式如下:
{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }}
请求体(request body)由文档的_source、文档所包含的一些字段以及其值,Index、create操作请求体需要这样指定;同样update操作也需要这样指定,而且请求体的组成应该与update API(doc,upsert,script等等)一致。删除操作不需要请求体(request body)。
{ "create": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title": "My first blog post" }
如果定义_id,ID将会被自动创建:
{ "index": { "_index": "website", "_type": "blog" }}
{ "title": "My second blog post" }
bulk请求表单如下:
curl -H "Content-Type:application/json" -XPOST localhost:9200/_bulk?pretty
{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "create": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title": "My first blog post" }
{ "index": { "_index": "website", "_type": "blog" }}
{ "title": "My second blog post" }
{ "update": { "_index": "website", "_type": "blog", "_id": "123", "_retry_on_conflict" : 3} }
{ "doc" : {"title" : "My updated blog post"} }
请注意delete行为(action)没有请求体,它紧接着另一个行为(action)。
上面请求响应结果包含一个items数组,其中包含每一个请求的结果,并且结果的顺序与请求的顺序相同:
{
"took": 4,
"errors": false,
"items": [
{ "delete": {
"_index": "website",
"_type": "blog",
"_id": "123",
"_version": 2,
"status": 200,
"found": true
}},
{ "create": {
"_index": "website",
"_type": "blog",
"_id": "123",
"_version": 3,
"status": 201
}},
{ "create": {
"_index": "website",
"_type": "blog",
"_id": "EiwfApScQiiy7TIKFxRCTw",
"_version": 1,
"status": 201
}},
{ "update": {
"_index": "website",
"_type": "blog",
"_id": "123",
"_version": 4,
"status": 200
}}
]
}}
每个子请求都被独立的执行,所以一个子请求的错误并不影响其它请求。如果任何一个请求失败,顶层的error标记将被设置为true,然后错误的细节将在相应的请求中被报告:
curl -H "Content-Type:application/json" -XPOST localhost:9200/_bulk?pretty
{ "create": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title": "Cannot create - it already exists" }
{ "index": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title": "But we can update it" }
响应中我们将看到create文档123失败了,因为文档已经存在,但是后面在123上执行的index请求成功了:
{
"took": 3,
"errors": true,
"items": [
{ "create": {
"_index": "website",
"_type": "blog",
"_id": "123",
"status": 409,
"error": "DocumentAlreadyExistsException
[[website][4] [blog][123]:
document already exists]"
}},
{ "index": {
"_index": "website",
"_type": "blog",
"_id": "123",
"_version": 5,
"status": 200
}}
]
}
返回结果中部分字段含义如表4-5所示:
字段 |
说明 |
"errors": true |
一个或多个请求失败 |
"status":409 |
这个请求的HTTP状态码被报告为409 CONFLICT |
"error":"DocumentAlreadyExistsException [[website][4] [blog][123]: document already exists]" |
错误消息说明了什么请求错误 |
"error":"DocumentAlreadyExistsException |
第二个请求成功了,状态码是200 OK |
这些说明bulk请求不是原子操作,它们不能实现事务。每个请求操作是分开的,所以每个请求的成功与否不干扰其它操作。
当在同一个index下的同一个type里批量索引日志数据,为每个文档指定相同的元数据是多余的。就像mget API,bulk请求也可以在URL中使用/_index或/_index/_type:
curl -H "Content-Type:application/json" -XPOST localhost:9200/website/_bulk?pretty
{ "index": { "_type": "log" }}
{ "event": "User logged in" }
整个批量请求需要被加载到接收请求节点的内存里,所以请求越大,给其它请求可用的内存就越小。有一个最佳的bulk请求大小,超过这个大小,性能不再提升而且可能降低。最佳大小,并不是一个固定的数字。它取决于硬件、文档的大小和复杂度以及索引和搜索的负载。
最佳点(sweetspot)取值方式如下:批量索引标准的文档,随着大小的增长,当性能开始降低,说明每个批次的大小太大了。开始的数量可以在1000~5000个文档之间,如果文档非常大,可以使用较小的批次。基于请求批次的物理大小也是比较重要的方式。一千个1kB的文档和一千个1MB的文档大不相同,一个好的批次最好保持在5-15MB。
简单查询语句(lite)是一种有效的命令行adhoc查询。对于善用搜索者,使用请求体查询(request body search)API是不可或缺的查询方式,这是因为大多数的参数以JSON格式定义而非查询字符串。
请求体查询(下文简称查询),并不仅仅用来处理查询,还可以高亮返回结果中的片段,并且标明用户最佳期望结果的相关数据。
我们以最简单的 search API开始,空查询将会返回索引中所有的文档。
curl –X GET localhost:9200/website/_search?pretty
{}
“{}”表明这是一个空查询数据。
同字符串查询一样,可以查询一个、多个或_all索引(indices)或类型(types):
curl –X GET localhost:9200/index1,index2/_search?pretty
{}
可以使用from及size参数进行分页:
curl –X GET localhost:9200/website/_search?pretty
{
"from": 30,
"size": 10
}
Elasticsearch的作者们倾向于使用GET提交查询请求,因为他们觉得这个词相比POST来说,能更好的描述这种行为。然而,因为携带交互数据的GET请求并不被广泛支持,所以searchAPI同样支持POST请求,类似于这样:
curl -H "Content-Type:application/json" –X POST localhost:9200/website/_search?pretty
{
"from": 30,
"size": 10
}
这个原理同样应用于其他携带交互数据的GETAPI请求中。
结构化查询是一种灵活的,多表现形式的查询语言。Elasticsearch在一个简单的JSON接口中用结构化查询来展现Lucene绝大多数能力。它使得查询更加灵活,精准,易于阅读并且易于debug。
使用结构化查询,你需要传递query参数:
curl –X GET localhost:9200/website/_search?pretty
{
"query": YOUR_QUERY_HERE
}
空查询 - {} - 在功能上等同于使用match_all查询子句,即匹配所有的文档:
curl –X GET localhost:9200/website/_search?pretty
{
"query": {
"match_all": {}
}
}
查询子句:一个查询子句一般使用如下结构:
{
QUERY_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,...
}
}
或指向一个指定的字段:
{
QUERY_NAME: {
FIELD_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,...
}
}
}
例如,你可以使用match查询子句用来找寻在tweet字段中找寻包含Elasticsearch的成员:
{
"match": {
"tweet": "Elasticsearch"
}
}
完整的查询请求如下:
curl –X GET localhost:9200/website/_search?pretty
{
"query": {
"match": {
"tweet": "Elasticsearch"
}
}
}
合并多子句:查询子句就像是搭积木一样,可以合并简单的子句为一个复杂的查询语句,比如:
· 叶子子句(leaf clauses)比如match子句,用以在将查询字符串与一个字段(或多字段)进行比较。
· 复合子句(compound)用以合并其他的子句。例如,bool子句允许合并其他的合法子句,must,must_not或者should,示例:
{
"bool": {
"must": { "match": { "tweet": "Elasticsearch" }},
"must_not": { "match": { "name": "mary" }},
"should": { "match": { "tweet": "full text" }}
}
}
复合子句能合并任意其他查询子句,包括其他的复合子句。这就意味着复合子句可以相互嵌套,从而实现非常复杂的逻辑。
示例:查询邮件正文中含有“businESs opportunity”字样的星标邮件或收件箱中正文中含有“businESs opportunity”字样的非垃圾邮件:
{
"bool": {
"must": { "match": { "email": "business opportunity" }},
"should": [
{ "match": { "starred": true }},
{ "bool": {
"must": { "folder": "inbox" }},
"must_not": { "spam": true }}
}}
],
"minimum_should_match": 1
}
}
使用模糊查询,你需要传递query和fuzzy参数
curl –X GET localhost:9200/website/mystyle/4?pretty
查询出如下内容:
{
"_index":"weibo",
"_type":"mystyle",
"_id":"4",
"_version":1,
"found":true,
"_source":{
"price":10,
"productID":"RTDK-193-JKHYS-YZK-IKDHJD-7",
"date":"2022-04-18 19:35:11"
}
}
RTDK-193-JKHYS-YZK-IKDHJD-7被默认的分词器分为rtdk、193、jkhys、yzk、ikdhjd和7,官网对分词后的字符模糊匹配规则如下:
0..2
must match exactly
3..5
one edit allowed
>5
two edits allowed
根据测试,此处字符长度应为输入查询字符,而不是分词后的字符。我们以三个字符yzk进行验证。
针对分词后的yzk,为三个字符,当使用yz查询时,结果如下:
curl -XGET http://101.8.134.2:9200/weibo/mystyle/_search?pretty -d '{"query":{"fuzzy":{"productID":"yz"}}}'
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 0,
"max_score" : null,
"hits" : [ ]
}
}
查询结果为空(如果按照分词后的yzk字符长度应该匹配规则3..5,使用yz符合相差一个字符的规则,应该会输出查询结果),说明使用yz查询时匹配0..2的规则,需要进行精准匹配,而分词后的内容不包含yz,所以查询结果为空,使用yzkd和yzb进行查询,结果如下:
curl -XGET http://101.8.134.2:9200/weibo/mystyle/_search?pretty -d '{"query":{"fuzzy":{"productID":"yzb"}}}'
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 0.49605155,
"hits" : [
{
"_index" : "weibo",
"_type" : "mystyle",
"_id" : "4",
"_score" : 0.49605155,
"_source" : {
"price" : 10,
"productID" : "RTDK-193-JKHYS-YZK-IKDHJD-7",
"date" : "2022-04-18 19:35:11"
}
}
]
}
}
符合3..5规则规定相差一个字符,也可使用5个字符进行测试。其他规则均按查询时字符串长度对应相应规则即可。
默认情况下,结果集会按照相关性进行排序,相关性越高,排名越靠前。
为了使结果可以按照相关性进行排序,需要一个相关性的值。在Elasticsearch的查询结果中,相关性的值会用_score字段来给出一个浮点型的数值,所以默认情况下,结果集以_score进行倒序排列。
有时,即便如此,还是没有一个有意义的相关性的值。比如,以下语句返回所有tweets中user_id是否包含值1。
curl –X GET localhost:9200/website/_search?pretty
{
"query" : {
"filtered" : {
"filter" : {
"term" : {
"user_id" : 1
}
}
}
}
}
过滤语句与_score没有关系,但是有隐含的查询条件match_all为所有的文档的_score设值为1。也就相当于所有的文档相关性是相同的。
下面例子中,对结果集按照时间排序,这也是最常见的情形,将最新的文档排列靠前。我们使用sort参数进行排序:
curl –X GET localhost:9200/website/_search?pretty
{
"query" : {
"filtered" : {
"filter" : { "term" : { "user_id" : 1 }}
}
},
"sort": { "date": { "order": "dESc" }}
}
响应:
"hits" : {
"total" : 6,
"max_score" : null,
"hits" : [ {
"_index" : "us",
"_type" : "tweet",
"_id" : "14",
"_score" : null, <1>
"_source" : {
"date": "2014-09-24",
...
},
"sort" : [ 1411516800000 ]
},
...
}
响应中"max_score"和"_score"表明_score字段没有经过计算,因为它没有用作排序。"sort"表明date字段被转为毫秒当作排序依据。
首先,在每个结果中增加了一个sort字段,它所包含的值是用来排序的。在这个例子当中date字段在内部被转为毫秒,即长整型数字1411516800000等同于日期字符串2014-09-24 00:00:00 UTC。
其次就是_score和max_score字段都为null。计算_score是比较消耗性能的,而且通常主要用作排序--不是用相关性进行排序的时候,就不需要统计其相关性。如果强制计算其相关性,可以设置track_scorES为true。
作为缩写,你可以只指定要排序的字段名称:
"sort": "number_of_children"
字段值默认以顺序排列,而_score默认以倒序排列。
如果合并一个查询语句,并且展示所有匹配的结果集使用第一排序是date,第二排序是_score,请求如下:
curl –X GET localhost:9200/website/_search?pretty
{
"query" : {
"filtered" : {
"query": { "match": { "tweet": "manage text search" }},
"filter" : { "term" : { "user_id" : 2 }}
}
},
"sort": [
{ "date": { "order": "dESc" }},
{ "_score": { "order": "dESc" }}
]
}
结果集会先用第一排序字段来排序,当用作第一字段排序的值相同的时候, 然后再用第二字段对第一排序值相同的文档进行排序,以此类推。
多级排序不需要包含_score--可以使用几个不同的字段,如位置距离或者自定义数值。
字符查询也支持自定义排序,在查询字符串使用sort参数就可以:
curl –X GET localhost:9200/website/_search?sort=date:dESc&sort=_score&q=search
一个拥有多值的字段就是一个集合,在为一个多值字段进行排序的时候,其实这些值本来是没有固定的顺序的。
对于数字和日期,你可以从多个值中取出一个来进行排序,支持使用min、max、avg或sum这些模式。比如可以在dates字段中用最早的日期来进行排序:
"sort": {
"dates": {
"order": "asc",
"mode": "min"
}
}
本节仅介绍基础用例,更多用法可以参考官方文档:
https://www.elastic.co/guide/en/elasticsearch/client/index.html
OpenJDK版本为1.8。
在pom文件中添加以下依赖:
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.6.2</version>
</dependency>
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.message.BasicHeader;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.client.*;
import java.io.IOException;
import java.util.Base64;
public class App {
public static void main(String[] args) throws IOException {
// 用户名
String username = "elastic";
// 密码
String password = "Admin@123";
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(HttpHost.create("10.121.93.12:9200")).setDefaultHeaders(
new Header[]{new BasicHeader("Authorization",
"Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes()))}));
// 查询集群健康状态
ClusterHealthResponse response = client.cluster().health(new ClusterHealthRequest(), RequestOptions.DEFAULT);
System.out.println(response);
client.close();
}
}
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.message.BasicHeader;
import org.elasticsearch.client.*;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import java.io.IOException;
import java.util.Base64;
public class App {
public static void main(String[] args) throws IOException {
// 用户名
String username = "elastic";
// 密码
String password = "Admin@123";
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(HttpHost.create("10.121.93.12:9200")).setDefaultHeaders(
new Header[]{new BasicHeader("Authorization",
"Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes()))}));
// 新建索引
CreateIndexResponse response = client.indices().create(new CreateIndexRequest("test1"), RequestOptions.DEFAULT);
System.out.println("response = " + response.index());
client.close();
}
}
Spark可以从Elasticsearch中读取数据,并运用Elasticsearch提供的过滤功能,在数据源头对数据进行过滤,可以避免将所有数据都加载到内存。
在pom文件中添加以下依赖:
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.11</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>org.Elasticsearch</groupId>
<artifactId>Elasticsearch-hadoop</artifactId>
<version>7.4.0</version>
</dependency>
完整代码如下:
import org.apache.spark.{SparkConf, SparkContext}
import org.Elasticsearch.spark._
object EsTest {
def main(args: Array[String]): Unit = {
case class Course(name: String, credit: Int)
val conf = new SparkConf().setAppName(this.getClass.getSimpleName).setMaster("local")
conf.set("es.nodes", "101.8.147.101")
conf.set("es.port", "9200")
conf.set("es.index.auto.create", "true")
val sc = new SparkContext(conf)
//rdd写es
val courseRdd = sc.makeRDD(Seq(Course("Hadoop", 4), Course("Spark", 3), Course("Kafka", 2)))
courseRdd.saveToEs("/course/rdd")
//rdd读es
val esCourseRdd = sc.esRDD("/course/rdd")
esCourseRdd.foreach(c => {
println(c.toString())
})
}
}
运行程序之后,数据可写入到Elasticsearch集群,在Web页面可查看写入的数据。
在迁移集群中的每个节点上安装sshfs,也可使用yum -y install fuse sshfs命令进行安装,无法用yum的话可使用以下步骤安装:
(1) 安装fuse,命令为:yum -y install fuse。如无法安装请按以下方式操作:
a. 下载fuse-2.7.4.tar.gz到服务器相关目录。
b. 解压,命令为tar -zxvf fuse-2.7.4.tar.gz,再运行./configure。
c. 运行make && make install进行安装。
d. 如在上面两步提示需要安装glibc相关组件等信息,请运行yum -y install gtk2 gtk2-devel gtk2-devel-docs安装glibc相关组件。
(2) 上传sshfs-2.8.tar.gz到相关目录中,解压命令为:tar -zxvf sshfs-2.8.tar.gz。
(3) 进入sshfs目录,命令为:cd sshfs-2.8。
(4) 编译,命令为:./configure。
(5) 安装,命令为:make && make install。
(6) 验证是否成功,命令为:sshfs -h。
在安装fuse与sshfs时,由于操作系统不同,通过yum安装的依赖可能会有差异,需要根据报错信息自行安装所需依赖。
图5-1 sshfs验证
(1) 选定Elasticsearch的任意一个节点的目录作为共享目录,并授读写权限,命令如下:
mkdir <共享目录>
chmod 777 <共享目录>
(2) 在每个节点的相同位置创建目录,并挂载共享目录。
a. 创建目录:
mkdir <Elasticsearch节点目录>
b. 授权:
chmod 777 <Elasticsearch节点目录>
c. 挂载共享目录:
sshfs root@<Elasticsearch_ip>:<共享目录> <Elasticsearch节点目录> -o allow_other
d. 测试 Elasticsearch用户是否对共享目录具有读写权限:
sudo -u Elasticsearch touch <共享目录>/test
(1) 进入Elasticsearch组件详情页,单击“配置”页签,进入配置管理页面。
(2) 打开elasticsearch-config,在content字段的文本框末尾添加以下配置:
path.repo: <Elasticsearch节点目录>
此处的Elasticsearch节点目录为2. 建立共享文件夹并挂载中创建的Elasticsearch节点目录。
(3) 修改配置,保存之后重启Elasticsearch集群。
(4) 重启后创建仓库:
curl -H 'Content-Type:application/json' -XPUT -u elastic:<password> http://<Elasticsearch_ip>:9200/<Backup_name> -d '{“type”:”fs”,”settings”:{“location”:” <Elasticsearch节点目录>”}}'
其中Backup_name表示备份名称。
· 备份所有索引:
curl -H 'Content-Type:application/json' -XPUT -u elastic:<password> http://<Elasticsearch_ip>:9200/_snapshot/<Backup_name>/snapshot_1
示例:
curl -H 'Content-Type:application/json' -XPUT -u elastic:<password> http://101.10.36.11:9200/_snapshot/my_backup/snapshot_1
· 备份部分索引:
curl -H 'Content-Type:application/json' -XPUT -u elastic:<password> http://<Elasticsearch_ip>/_snapshot/<Backup_name>/snapshot_1 -d '{“indices”:”<Indices_name>”}'
示例:
curl -H 'Content-Type:application/json' -XPUT -u elastic:<password> http://101.10.36.11:9200/_snapshot/my_backup/snapshot_1 -d '{“indices”:”panabit-2018*”}'
· 备份单个索引,多个索引备份部分:
curl -H 'Content-Type:application/json' -XPUT -u elastic:<password> http://<Elasticsearch_ip>:9200/_snapshot/<Backup_name>/snapshot_1 -d '{“indices”:” <Indices_name>”}'
示例:
curl -H 'Content-Type:application/json' -XPUT -u elastic:<password> http://101.10.36.11:9200/_snapshot/my_backup/snapshot_1 -d '{“indices”:”panabit-2018.01.28, panabit-2018.01.29”}'
· 查看备份状态:
curl -H 'Content-Type:application/json' -XGET -u elastic:<password> http://<Elasticsearch_ip>:9200/_snapshot/<Backup_name>/snapshot_1/_status
示例:
curl -H 'Content-Type:application/json' -XGET -u elastic:<password> http://101.10.36.11:9200/_snapshot/my_backup/snapshot_1/_status
· 查看备份信息:
curl -H 'Content-Type:application/json' –XGET -u elastic:<password> http://<Elasticsearch_ip>:9200/_snapshot/<Backup_name>/snapshot_1
示例:
curl -H 'Content-Type:application/json' -XGET -u elastic:<password> http://101.10.36.11:9200/_snapshot/my_backup/snapshot_1
图5-2 备份数据文件
(1) 在数据迁移的目标集群中重复步骤:1. 安装sshfs、2. 建立共享文件夹并挂载、3. 修改Elasticsearch集群配置。
(2) 将源集群的备份内容(<Elasticsearch节点目录>里面的所有文件),复制到目标的集群仓库目录里。
(3) 使用Restful API进行备份的恢复:
curl XGET -u elastic:<password> http://<Elasticsearch_ip>:9200/_snapshot/<Backup_name>/snapshot_1/_restore
(4) 查看恢复状态:
curl -XGET -u elastic:<password> http://<Elasticsearch_ip>:9200/_recovery
(5) 查看数据信息:
curl -XGET -u elastic:<password> http://<Elasticsearch_ip>:9200/_cat/indices?v
· 如果查询有一个过滤字段并且它的值是可枚举的,那么把数据分成多个索引。
· 如果查询具有过滤字段并且其值不可枚举,请使用路由。可以通过使用过滤字段值作为路由键来将索引拆分成多个分片,然后删除过滤条件。
· 如果查询条件包含日期范围,则按日期对数据进行分组。这适用于大多数日志记录或监控场景。可以以每天、每周或每月分组索引,然后可以在指定的日期范围内获得索引列表。Elasticsearch只需要查询一个较小的数据集而不是整个数据集。此外,当数据过期时,很容易缩小/删除旧的索引。
· 明确地设置映射。Elasticsearch可以动态地创建映射,但并不适用于所有场景。例如,Elasticsearch中默认的字符串字段映射是“关键字”和“文本”类型,这在很多场景下是没有必要的。
· 如果文档使用用户定义的ID或路由索引,请避免不平衡分片。Elasticsearch采用随机ID生成器和哈希算法来确保文档均匀地分配给分片。当使用用户定义的ID或路由时,ID或路由键可能不够随机,并且一些分片可能明显比其它分片更大。在这种情况下,在这个分片上的读/写操作将比在其它分片上慢得多。可以优化ID或路由键。
· 使分片均匀分布在节点上。如果一个节点比其它节点有更多的分片,则会比其它节点承担更多的负载,并很有可能成为整个系统的瓶颈。
· 使用批量请求。
· 使用多个线程/工作来发送请求。
· 增加刷新间隔。每次刷新事件发生时,Elasticsearch都会创建一个新的Lucene段,并在稍后进行合并。增加刷新间隔将降低创建/合并的成本。请注意,只有在刷新事件发生后才能进行文件搜索。
· 减少副本数量。Elasticsearch需要为每个索引请求将文档写入主要和所有副本分片。显然,一个大的副本数会减慢索引速度,但另一方面,增加副本数量将提高搜索性能。副本的作用一是提高系统的容错性,当某个节点某个分片损坏或丢失时可以从副本中恢复;二是提高Elasticsearch的查询效率,Elasticsearch会自动对搜索请求进行负载均衡。
· 如果可能,使用自动生成的ID。Elasticsearch自动生成的ID可以确保是唯一的,以避免版本查询。如果客户真的需要使用自定义的ID,建议选择一个对Lucene友好的ID,比如零填充顺序ID,UUID-1或者Nano time。这些ID具有一致的顺序模式,压缩良好。相比之下,像UUID-4这样的ID本质上仍旧是随机的,它提供了较差的压缩比,并降低了Lucene的速度。
· 一般情况下最好使用过滤语境而不是查询语境。一个查询子句用于回答“这个文档如何与查询子句匹配?”,过滤子句用于回答“这个文档是否匹配这个过滤子句?”。Elasticsearch只需要回答“是”或“否”。它不需要计算过滤子句的相关性得分,并且可以高速缓存过滤结果。
· 增加刷新间隔。正如在调优索引性能部分所提到的,Elasticsearch每次刷新时都会创建一个新的段。增加刷新间隔将有助于减少段数并降低搜索的I/O成本。而且一旦发生刷新并且数据改变,缓存将无效。增加刷新间隔可以使Elasticsearch更高效地利用缓存。
· 增加副本数量。Elasticsearch可以在主分片或副本分片上执行搜索。拥有的副本越多,搜索中涉及的节点就越多。
· 尝试不同的分片数量。太小的分片数量会使搜索无法扩展。例如,如果分片数量设置为1,则索引中的所有文档都将存储在一个分片中。如果文件很多,查询将耗费大量时间。另一方面,创建索引的分片太多也会对性能造成危害,因为Elasticsearch需要在所有分片上运行查询,除非在请求中指定了路由键,然后将所有返回的结果一起取出并合并。
· 根据经验,如果索引小于1G,可以将分片数设置为1。对于大多数情况,可以将分片数保留为默认值5,但是如果分片大小超过30GB,应该增加分片数量将索引分成更多的分片。
· 节点查询缓存。节点查询缓存只缓存正在过滤语境中使用的查询。与查询子句不同,过滤子句是“是”或“否”的问题。Elasticsearch使用一个位设置机制来缓存过滤结果,以便后面的查询使用相同的过滤条件进行加速。请注意,只有保存超过10,000个文档的分段(或文档总数的3%,以较大者为准)才能启用节点查询缓存。
· 分片查询缓存。如果大多数查询是聚合查询,应该使用分片查询缓存,它可以缓存聚合结果,以便Elasticsearch直接以低成本提供请求。
· 仅检索必要的字段。如果文档很大,并且只需要几个字段,请使用 stored_fields 检索所需要的字段而不是所有字段。
· 避免搜索停用词。诸如“a”和“the”这样的停用词可能导致查询命中结果计数爆炸。设想有一百万个文件,搜索“fox”可能会返回几十个结果,但搜索“the fox”可能会返回索引中的所有文件,因为“the”出现在几乎所有的文件中。
Elasticsearch需要对所有命中的结果进行评分和排序,导致像“the fox”这样的查询减慢整个系统。可以使用停止标记过滤来删除停用词,或使用“和”运算符将查询从“the fox”更改为“the AND fox”,以获得更精确的结果。如果某些词在索引中经常使用,但不在默认停用词列表中,则可以使用截止频率来动态处理它们。
· 如果不关心文档返回的顺序,则按_doc排序。Elasticsearch使用“_score”字段按默认分数排序。如果不关心顺序,可以使用“sort”:“_doc”让Elasticsearch按索引顺序返回。
· 避免使用脚本查询来计算不固定的匹配。在索引时存储计算的字段。例如,有一个包含大量用户信息的索引,需要查询以“1234”开头的所有用户。或许想运行一个脚本查询,如“source”:“doc [‘num’].value.startsWith(’1234’)。”这个查询是非常耗费资源的,并且减慢整个系统。索引时考虑添加一个名为“num_prefix”的字段,然后只需要查询“name_prefix”:“1234”。
· 避免通配符查询。
如果在集群管理页面,看到组件列表中Elasticsearch的状态为已停止,则表示Elasticsearch已经停止运行,如图6-1所示。
造成组件停止的原因可能有以下几个:
· 端口号被占用
在linux shell终端输入netstat -anp | grep 9200,查看端口是否被别的进程占用,如果被占用就杀掉该进程的进程号,然后重启组件。
· 主机故障
组件所在的主机发生故障。前往主机页面查看Elasticsearch组件所在的主机是否正常。
· 其他原因
登录出现问题的Elasticsearch节点,根据日志文件的报错信息进行问题定位。
所谓脑裂问题,就是同一个集群中的不同节点对集群的状态有了不一样的理解。正常情况下,集群中的所有节点应该对集群中Master的选择是一致的;当集群中的节点对Master节点的选择出现不一致时就产生了脑裂问题。脑裂状态将导致集群不能正常工作。
通过以下命令查看集群状态,发现集群的总体状态是red,在结果中显示的节点数量与实际不一致,并且将请求发向不同的节点之后,可用的节点数量不一致,此时就是出现了脑裂问题。
curl -XGET 'node1:9200/_cluster/health'
可能导致脑裂的原因:
· 网络:网络问题造成某些节点认为Master死掉了,重新选择了一个Master。网络正常之后,原来的Master节点重新加入集群,导致出现两个Maser。
· 节点负载:当Master节点与Data节点混在一起时,可能会因为工作节点的负载较大导致Master停止响应,此时一部分节点就会认为这个Master节点失效了,故重新选举新的Master,这时就出现了脑裂。
当集群中出现脑裂时,可以重启整个Elasticsearch集群,让集群中的节点重新选举出一个Master。
针对独立云服务中的Elasticsearch集群,可以配置专有master实例,实现master实例和Data实例分离,专有master实例个数为奇数且至少3个。
不同款型规格的资料略有差异, 详细信息请向具体销售和400咨询。H3C保留在没有任何通知或提示的情况下对资料内容进行修改的权利!