赞
踩
本文示例以 ElasticSearch 8.6.2 版本演示,更详细的 API 参数及用法请参考官方文档。测试命令我用的是 Kibana,在输入时会有命令和语法错误提示,可直接复制 CURL 格式、格式化、查看文档,点击导航栏上面的 help,也提供了一些快捷方式,方便学习。
API 测试参考:
Elasticsearch 请求示例
Elasticsearch 8.6 - REST APIs
elasticsearh中查询类型
ES cat
命令是监控 ES 的节点,内存,索引,分片,集群状态等一些基本信息。
GET /_cat/<some>
路径参数:
<some>
(必需,字符串)节点,内存,索引,分片,集群状态等一些基本信息
请求参数:
v: 显示详细的查询结果。
help: 帮助了解cat 相关指令支持哪些功能,返回参数第一列显示完整的名称,第二列显示缩写,第三列提供了关于这个参数的简介。
h: 指定字段输出。
GET /_cat/nodes?v
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
127.0.0.1 22 97 4 0.00 0.03 0.05 cdfhilmrstw * VM-0-12-centos
IP:(默认)IP 地址
heap.percent:(默认)最大配置堆数
ram.percent:(默认)已用内存总百分比
返回结果:堆内存,内存,cpu百分比, 最近1,5,15分钟 节点的负载,显示主节点( * 标记主节点),节点名等信息。
GET /_cat/allocation?v
shards disk.indices disk.used disk.avail disk.total disk.percent host ip node
12 53.3mb 13.7gb 35.2gb 49gb 28 127.0.0.1 127.0.0.1 VM-0-12-centos
1 UNASSIGNED
返回结果:节点分片数,索引占用磁盘大小,磁盘已使用容量大小,磁盘可用容量大小,磁盘总容量大小,磁盘使用率等节点信息。
GET /_cat/indices?v
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open test Ygi2jIdzTsOgn2Aw9KFeVg 1 1 3 1 15.7kb 15.7kb
返回结果:索引的健康状态,索引名,索引主分片,副本大小,文档数,被删除文档数,索引主分片,副本 总占用存储空间。
GET /_cat/shards?v index shard prirep state docs store ip node .apm-agent-configuration 0 p STARTED 0 225b 127.0.0.1 VM-0-12-centos .kibana_security_session_1 0 p STARTED 5 31.2kb 127.0.0.1 VM-0-12-centos .security-7 0 p STARTED 113 329.5kb 127.0.0.1 VM-0-12-centos .geoip_databases 0 p STARTED 41 42.3mb 127.0.0.1 VM-0-12-centos test 0 p STARTED 3 15.7kb 127.0.0.1 VM-0-12-centos test 0 r UNASSIGNED .apm-custom-link 0 p STARTED 0 225b 127.0.0.1 VM-0-12-centos .kibana_task_manager_8.6.2_001 0 p STARTED 27 7.8mb 127.0.0.1 VM-0-12-centos .kibana_8.6.2_001 0 p STARTED 1135 2.7mb 127.0.0.1 VM-0-12-centos .security-profile-8 0 p STARTED 1 8.5kb 127.0.0.1 VM-0-12-centos .kibana-event-log-8.6.2-000001 0 p STARTED 22 32.6kb 127.0.0.1 VM-0-12-centos .ds-.logs-deprecation.elasticsearch-default-2023.02.21-000001 0 p STARTED 2 23.6kb 127.0.0.1 VM-0-12-centos .ds-ilm-history-5-2023.02.21-000001 0 p STARTED 9 28.3kb 127.0.0.1 VM-0-12-centos
返回结果:索引名称,分片序号,主副分片标志,该分片存储空间,分片存储的文档数,分片所属节点ip,节点名。
GET /_cat/health?v
epoch timestamp cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1677579030 10:10:30 elasticsearch yellow 1 1 12 12 0 0 1 0 - 92.3%
返回结果:集群名称,集群状态,节点数,数据节点数,分片数,主分片数,激活的分片百分比(active_shards_percent)。
GET /_cat/aliases?v
alias index filter routing.index routing.search is_write_index
.security .security-7 - - - -
.kibana .kibana_8.6.2_001 - - - -
.kibana_8.6.2 .kibana_8.6.2_001 - - - -
.kibana_task_manager .kibana_task_manager_8.6.2_001 - - - -
.kibana_task_manager_8.6.2 .kibana_task_manager_8.6.2_001 - - - -
.security-profile .security-profile-8 - - - -
.kibana_security_session .kibana_security_session_1 - - - -
.kibana-event-log-8.6.2 .kibana-event-log-8.6.2-000001 - - - true
GET /_cat/master?v
id host ip node
VZje5HgCRDerg5Fp6bWDUA 127.0.0.1 127.0.0.1 VM-0-12-centos
快速查询当前整个集群或者指定索引的document的数量(不包括删除的但是还没有清理掉的document)。
GET /_cat/master?v
epoch timestamp count
1677579205 10:13:25 3
获取集群的健康状态有两种方式:
语法:
GET /_cluster/health/<target>
路径参数:
<target>
(可选,字符串) 用于限制的数据流、索引和索引别名的逗号分隔列表 请求。支持通配符表达式 ()。*
要定位集群中的所有数据流和索引,请省略此参数或使用 或 。_all*
测试:
//请求: GET /_cluster/health //返回: { "cluster_name": "elasticsearch", # 集群名,默认elasticsearch "status": "green", # 集群状态 "timed_out": false, # 是否超时 "number_of_nodes": 1, # 节点数量 "number_of_data_nodes": 1, # 数据节点数量 "active_primary_shards": 11, # 活动主分片的数量 "active_shards": 11, # 活动主分片和副本分片的总数 "relocating_shards": 0, # 正在重新定位的分片数 "initializing_shards": 0, # 正在初始化的分片数 "unassigned_shards": 0, # 未分配的分片数 "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": 100 # 集群中活动分片的比率,以百分比表示 }
返回用于调试或诊断问题的集群内部状态的信息。
语法:
GET /_cluster/state/<metrics>/<target> 路径参数: <metrics> (可选,字符串)以下选项的逗号分隔列表: _all 显示所有指标。 blocks 显示响应的一部分。blocks master_node 显示响应的一部分。master_node metadata 显示响应的一部分。如果提供逗号分隔 索引列表,返回的输出将仅包含这些索引的元数据 指标。metadata nodes 显示响应的一部分。nodes routing_nodes 显示响应的一部分。routing_nodes routing_table 显示响应的一部分。如果您提供逗号 分离的索引列表,返回的输出将仅包含 这些索引的路由表。routing_table version 显示群集状态版本。 <target> (可选,字符串)数据流、索引和别名的逗号分隔列表 用于限制请求。支持通配符 ()。以所有数据流为目标 和索引,省略此参数或使用或 .**_all
测试:
//请求: GET /_cluster/state //返回: { "cluster_name": "elasticsearch", # 集群名 "cluster_uuid": "MtNAAgvNQhmc1W3u9ytePQ", # 集群ID "version": 109, # state命令版本 "state_uuid": "M9oKz-6PTY2KWOkLDo8MkQ", # state ID "master_node": "VZje5HgCRDerg5Fp6bWDUA", # 主节点ID "blocks": {}, # 系统限制信息,响应的blocks部分 "nodes": {...}, # 节点信息 "metadata": {...} # 元数据信息,响应的metadata部分。如果提供了路径参数index,则只返回指定索引的metadata信息 } //请求: GET /_cluster/state/nodes //返回: { "cluster_name": "elasticsearch", # 集群名 "cluster_uuid": "MtNAAgvNQhmc1W3u9ytePQ", # 集群ID "nodes": { # 节点信息 "VZje5HgCRDerg5Fp6bWDUA": { # 节点ID "name": "VM-0-12-centos", # 节点名 "ephemeral_id": "_6rakwKVQE62G5O0i9ohyw", # 临时ID "transport_address": "127.0.0.1:9300", # 节点之间的通讯地址 "external_id": "VM-0-12-centos", # 对外显示的节点名 "attributes": { # 属性 "ml.max_jvm_size": "1048576000", # JVM 最大内存 "ml.allocated_processors": "1", # 分配的处理器数 "ml.machine_memory": "2095960064", # 内存大小 "xpack.installed": "true", # xpack 认证 "ml.allocated_processors_double": "1.0" # 分配的处理器_双重 }, "roles": [ # 节点角色,默认全部角色 "data", # 数据节点 "data_cold", # 冷数据节点 "data_content", # 内容数据节点 "data_frozen", # 冻结数据节点 "data_hot", # 热数据节点 "data_warm", # 暖数据节点 "ingest", # 预处理节点 "master", # 主节点 "ml", # 机器学习节点 "remote_cluster_client", # 跨集群客户端节点 "transform" # 转换节点 ] } } }
返回群集节点信息。
GET /_nodes GET /_nodes/<node_id> GET /_nodes/<metric> GET /_nodes/<node_id>/<metric> 路径参数: <metric> (可选,字符串) 将返回的信息限制为特定指标。支持 逗号分隔的列表,例如 。http,ingest 的有效值<metric> aggregations 有关可用聚合类型的信息。 http 有关此节点的 HTTP 接口的信息。 indices 与索引相关的节点级配置: total_indexing_buffer:此节点上索引缓冲区的最大大小。 ingest 有关引入管道和处理器的信息。 jvm JVM 信息,包括其名称、版本和配置。 os 操作系统信息,包括其名称和版本。 plugins 有关每个节点安装的插件和模块的详细信息。以下 每个插件和模块都有可用的信息: name:插件名称 version:插件构建的 Elasticsearch 版本 description:插件用途的简短描述 classname:插件入口点的完全限定类名 has_native_controller:插件是否具有本机控制器 过程 process 进程信息,包括数字进程 ID。 settings 列出文件中定义的所有正在使用的节点设置。elasticsearch.yml thread_pool 有关每个线程池的配置的信息。 transport 有关节点的传输接口的信息。 如果您使用此 API 的完整形式,那么您 还可以请求指标以检索所有指标,或者您可以请求 用于抑制所有指标并仅检索 节点。GET /_nodes/<node_id>/<metric>_all_none <node_id> (可选,字符串)以逗号分隔的节点 ID 或名称列表,用于限制 返回的信息。
测试:
//请求: GET /_nodes //返回: { "_nodes": { # 节点数量信息 "total": 1, # 节点数量 "successful": 1, # 正常节点数量 "failed": 0 # 错误节点数量 }, "cluster_name": "elasticsearch", # 集群名 "nodes": { # 节点信息 "VZje5HgCRDerg5Fp6bWDUA": { "name": "VM-0-12-centos", "transport_address": "127.0.0.1:9300", "host": "127.0.0.1", "ip": "127.0.0.1", "version": "8.6.2", "build_flavor": "default", "build_type": "tar", "build_hash": "2d58d0f136141f03239816a4e360a8d17b6d8f29", "total_indexing_buffer": 104857600, "roles": [ # 节点角色,没有设置默认所有角色 "data", # 数据节点 "data_cold", # 冷数据节点 "data_content", # 内容数据节点 "data_frozen", # 冻结数据节点 "data_hot", # 热数据节点 "data_warm", # 暖数据节点 "ingest", # 预处理节点 "master", # 主节点 "ml", # 机器学习节点 "remote_cluster_client", # 跨集群客户端节点 "transform" # 转换节点 ], "attributes": {...}, # 节点属性 "settings": {...}, # 节点设置 "os": {...}, # 操作系统信息 "process": {...}, # 进程信息 "jvm": {...}, # JVM 信息 "thread_pool": {...}, # 线程池配置信息 "transport": {...}, # 节点传输接口信息 "http": {...}, # 节点 HTTP 接口信息 "plugins": {...}, # 节点安装的插件和模块的详细信息 "modules": {...}, # 节点的模块信息 "ingest": {...}, # 有关引入管道和处理器的信息 "aggregations": {...} # 有关可用聚合类型的信息 } } }
语法:
HEAD <index>
测试:
//请求:
HEAD test
//存在返回:
200 - OK
//不存在返回:
{
"statusCode": 404,
"error": "Not Found",
"message": "404 - Not Found"
}
没有索引前,第一次创建文档的时候也会创建索引。
语法:
PUT <index> { "aliases": {}, # 别名 "mappings": {}, # 映射 "settings": {}, # 配置 } 路径参数: <index> (必需,字符串)要创建的索引的名称。 请求体: <aliases> (可选,对象的对象)索引的别名。 <mappings> (可选,映射对象)索引中字段的映射。如果 指定时,此映射可以包括: 字段名称 字段数据类型 映射参数 请参阅 映射:https://www.elastic.co/guide/en/elasticsearch/reference/8.6/mapping.html。 <settings> (可选,索引设置对象)配置 索引的选项。 请参阅索引设置:https://www.elastic.co/guide/en/elasticsearch/reference/8.6/index-modules.html#index-modules-settings。
索引名称必须满足以下条件:
\
, /
,*
,?
, "
,<
,>
,|
,
(空格),,
,#
:
,但该冒号已弃用,在 7.0+ 中不受支持_
,-
,+
开头.
或 ..
.
开头的名称已被弃用,隐藏索引和插件管理的内部索引除外.测试:
//请求: PUT test //返回: { "acknowledged": true, "shards_acknowledged": true, "index": "test" } //请求: GET test //返回: { "test": { "aliases": {}, "mappings": {}, "settings": { "index": { "routing": { "allocation": { "include": { "_tier_preference": "data_content" } } }, "number_of_shards": "1", "provided_name": "test", "creation_date": "1677306509277", "number_of_replicas": "1", "uuid": "tXKSzCSUQNWxnDhqeBrLeA", "version": { "created": "8060299" } } } } }
创建索引时有三个重要的参数:aliases
,mappings
,settings
:
ES 的 aliases(别名)
就类似数据库的视图,我们为索引 test
创建一个别名 test_alias
,这样我们对 test_alias
的操作就像对 test
的操作一样。
//请求: POST _aliases { "actions": [ { "add": { "index": "test", "alias": "test_alias" } } ] } //返回: { "acknowledged": true } //请求: GET _cat/aliases //返回: alias index filter routing.index routing.search is_write_index .security .security-7 - - - - test_alias test - - - - .kibana .kibana_8.6.2_001 - - - - .kibana_8.6.2 .kibana_8.6.2_001 - - - - .kibana_task_manager .kibana_task_manager_8.6.2_001 - - - - .kibana_task_manager_8.6.2 .kibana_task_manager_8.6.2_001 - - - - .kibana_security_session .kibana_security_session_1 - - - - .security-profile .security-profile-8 - - - - .kibana-event-log-8.6.2 .kibana-event-log-8.6.2-000001 - - - true
别名不仅仅可以关联一个索引,它能聚合多个索引。也对于同一个index,给不同人看到不同的数据,假设 test
有个字段是 team
,team
字段记录了该数据是哪个人添加的,设置别名可以使不同人之间的 team
数据是不可见的。
可参考:Elasticsearch基础11——索引之别名使用。
ES 的 mappings(映射)
相当于数据库中的表结构,对表的字段类型长度索引做设置,而在 ES 中 映射是定义一个文档和它所包含的字段如何被存储和索引的过程,分为 自动映射(Dynamic mapping)
和 显式映射(Explicit mapping)
。
动态映射:
- 动态映射允许您试验 并在刚开始时探索数据。Elasticsearch 添加了新字段 自动,只需为文档编制索引即可。您可以将字段添加到顶级 映射,以及内部对象和嵌套字段。
- 使用动态模板定义自定义映射,这些映射是 应用于基于匹配条件动态添加的字段。
显式映射:
显式映射允许您精确选择如何 定义映射定义,例如:
- 哪些字符串字段应被视为全文字段。
- 哪些字段包含数字、日期或地理位置。
- 日期值的格式。
- 用于控制动态添加字段映射的自定义规则。
使用运行时字段进行架构更改,而无需 重新索引。可以将运行时字段与索引字段结合使用,以 平衡资源使用情况和性能。您的索引会更小,但 搜索性能较慢。
在ElasticSearch中一旦创建了映射是不被允许进行修改的,因为对于数据存储、分析、检索,都是按照mapping 中的配置进行的,如果前期 根据 mapping存储好了之后,又对 mapping 进行更改,那么就会导致前面存储的数据和后面的检索策略后面的存储 数据不一致的情况,导致检索行为不准确。 只能在创建index 的时候手动配置 mapping,或者新增 fieId mapping。
测试:
给索引test
设置映射,id:long
,name:keyword
。
//请求: POST test/_doc/_mapping { "properties":{ "id":{ "type":"long" }, "name":{ "type":"keyword" } } } //返回: { "_index": "test", "_id": "_mapping", "_version": 1, "result": "created", # 创建成功 "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 0, "_primary_term": 1 } //请求: GET test/_mapping //返回: { "test": { "mappings": { "properties": { "id": { "type": "long" }, "name": { "type": "keyword" } } } } }
索引的配置项可以分为 静态配置
与 动态配置
,所谓的静态配置即索引创建后不能修改。
index.number_of_shards
:索引分片的数量。在ES层面可以通过es.index.max_number_of_shards属性设置索引最大的分片数,默认为1024,index.number_of_shards的默认值为Math.min(es.index.max_number_of_shards,5),故通常默认值为5。index.shard.check_on_startup
:分片在打开之前是否应该检查该分片是否损坏。当检测到损坏时,它将阻止分片被打开。可选值:false:不检测;checksum:只检查物理结构;true:检查物理和逻辑损坏,相对比较耗CPU;fix:类同与false,7.0版本后将废弃。默认值:false。index.codec
:数据存储的压缩算法,默认值为LZ4,可选择值best_compression ,比LZ4可以获得更好的压缩比(即占据较小的磁盘空间,但存储性能比LZ4低)。index.routing_partition_size
:路由分区数,如果设置了该参数,其路由算法为:(hash(_routing) + hash(_id) % - index.routing_parttion_size ) % number_of_shards。如果该值不设置,则路由算法为 hash(_routing) % number_of_shardings,_routing默认值为_id。更多配置这里不多说,可参考https://cloud.tencent.com/developer/article/1443568。
//请求: GET /test/_settings //返回: { "test": { "settings": { "index": { "routing": { "allocation": { "include": { "_tier_preference": "data_content" } } }, "number_of_shards": "1", "provided_name": "test", "creation_date": "1677313859733", "number_of_replicas": "1", "uuid": "SWZ28NdRRsCgcgWlyjmePQ", "version": { "created": "8060299" } } } } }
语法:
GET /<index> # 查看指定索引信息
GET _cat/indices # 查看所有索引
测试:
//请求: GET /test //返回: { "test": { "aliases": {}, "mappings": {}, "settings": { "index": { "routing": { "allocation": { "include": { "_tier_preference": "data_content" } } }, "number_of_shards": "1", "provided_name": "test", "creation_date": "1677306509277", "number_of_replicas": "1", "uuid": "tXKSzCSUQNWxnDhqeBrLeA", "version": { "created": "8060299" } } } } } //请求: GET _cat/indices?v //返回: health status index uuid pri rep docs.count docs.deleted store.size pri.store.size yellow open test tXKSzCSUQNWxnDhqeBrLeA 1 1 0 0 225b 225b
语法:
DELETE <index>
测试:
//请求:
DELETE test
//返回:
{
"acknowledged": true
}
//请求:
GET _cat/indices
//返回:
# 空
语法:
HEAD <index>/_doc/<_id>
HEAD <index>/_source/<_id>
路径参数:
<index>
(必需,字符串)包含文档的索引的名称。
<_id>
(必需,字符串)文档的唯一标识符。
测试:
//请求:
HEAD test/_doc/1
//存在返回:
200 - OK
//不存在返回:
{
"statusCode": 404,
"error": "Not Found",
"message": "404 - Not Found"
}
索引文档就是创建文档,这里的索引表示创建文档这个动作。
语法:
PUT /<target>/_doc/<_id>
POST /<target>/_doc/<_id>
PUT /<target>/_create/<_id>
POST /<target>/_create/<_id>
路径参数:
<target>
(必需,字符串)目标数据流或索引的名称。
<_id>
(可选,字符串)文档的唯一标识符。省略此参数会自动生成文档 ID。
测试:
//请求: POST test/_doc/1 { "id":"1", "name":"张三", "avatar":"https://profile-avatar.csdnimg.cn/21f4a00156854dcab8a86032bf5b9068_weixin_43844718.jpg!0", "age":20 } //返回: { "_index": "test", # 文档所在索引 "_id": "1", # 文档ID,这是ES 的文档ID 和 源数据中的id关联需要业务维护 "_version": 1, # 版本 "result": "created", # 执行结果 - 成功 "_shards": { # 分片 "total": 2, # 分片总数 - 一主一副 "successful": 1, # 正常运行的分片数量,因为是单机,主副分片在一起,只会使用主分片 "failed": 0 # 失败数量,副分片没用到并不是运行失败,主副分片本就是为了数据冗余而存在的,单机的话副分片就用不到了,宕机一起死 }, "_seq_no": 1, # _seq_no是严格递增的顺序号,每个文档一个,Shard级别严格递增,保证后写入的Doc的_seq_no大于先写入的Doc的_seq_no。任何类型的写操作,包括index、create、update和Delete,都会生成一个_seq_no。 "_primary_term": 1 # _primary_term主要是用来恢复数据时处理当多个文档的_seq_no一样时的冲突,比如当一个shard宕机了,raplica需要用到最新的数据,就会根据_primary_term和_seq_no这两个值来拿到最新的document } //测试: POST test/_doc { "id":"2", "name":"李四", "avatar":"https://profile-avatar.csdnimg.cn/21f4a00156854dcab8a86032bf5b9068_weixin_43844718.jpg!0", "age":22 } //返回: { "_index": "test", "_id": "Ra20kIYBD3T716opayt9", # 自动生成的文档ID "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 2, "_primary_term": 1 }
测试:
test2
,那么在第一次创建文档的时候会自动创建 test2
。//请求: GET _cat/indices //返回: health status index uuid pri rep docs.count docs.deleted store.size pri.store.size yellow open test SWZ28NdRRsCgcgWlyjmePQ 1 1 1 0 5.4kb 5.4kb //请求: POST test2/_doc/1 { "id":"1", "name":"张三", "avatar":"https://profile-avatar.csdnimg.cn/21f4a00156854dcab8a86032bf5b9068_weixin_43844718.jpg!0", "age":20 } //返回: { "_index": "test2", "_id": "1", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 0, "_primary_term": 1 } //请求: GET _cat/indices //返回: health status index uuid pri rep docs.count docs.deleted store.size pri.store.size yellow open test2 ssrY7_QvQHCEHyxbYIW2FQ 1 1 1 0 6.5kb 6.5kb yellow open test SWZ28NdRRsCgcgWlyjmePQ 1 1 1 0 5.4kb 5.4kb
语法:
# 获取索引下所有文档 GET /<index>/_search # 获取指定文档 GET <index>/_doc/<_id> GET <index>/_source/<_id> 路径参数: <index> (必需,字符串)包含文档的索引的名称。 <_id> (必需,字符串)文档的唯一标识符。 部分查询参数,详细用法参考官网(https://www.elastic.co/guide/en/elasticsearch/reference/8.6/docs-get.html#docs-get-api-prereqs): stored_fields (可选,布尔值)如果 ,则检索存储在 索引而不是文档。默认值为false 。 _source (可选,字符串)真或假返回字段与否,或 要返回的字段列表。 version (可选,整数)用于并发控制的显式版本号。 指定的版本必须与文档的当前版本匹配 请求成功。
这里关于获取文档返回信息中的参数叫做 元数据
:
true
或 false
。found
是 true
,则包含以 JSON 格式设置的文档数据。如果 _source
参数设置为 false
或 stored_fields
参数设置为 true
,则排除。注意:元数据和源数据不要搞混了,源数据是元数据 _source 下的内容,就是我们存到 ES 中的信息。
测试:
//请求: GET test/_doc/1 //返回: { "_index": "test", # 索引 "_id": "1", # 文档ID "_version": 1, # 版本号 "_seq_no": 1, # 顺序号 _seq_no和_primary_term 共同用于版本控制 "_primary_term": 1, # 编号 "found": true, # 是否找到 "_source": { # 源数据,存到ES中的数据 "id": "1", "name": "张三", "avatar": "https://profile-avatar.csdnimg.cn/21f4a00156854dcab8a86032bf5b9068_weixin_43844718.jpg!0", "age": 20 } } //请求: GET test/_source/1 //返回: { "id": "1", "name": "张三", "avatar": "https://profile-avatar.csdnimg.cn/21f4a00156854dcab8a86032bf5b9068_weixin_43844718.jpg!0", "age": 20 } //请求: GET /test/_search //返回: { "took": 0, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 3, "relation": "eq" }, "max_score": 1, "hits": [ { "_index": "test", "_id": "_mapping", "_score": 1, "_source": { "properties": { "id": { "type": "long" }, "name": { "type": "keyword" } } } }, { "_index": "test", "_id": "1", "_score": 1, "_source": { "id": "1", "name": "张三", "avatar": "https://profile-avatar.csdnimg.cn/21f4a00156854dcab8a86032bf5b9068_weixin_43844718.jpg!0", "age": 20 } }, { "_index": "test", "_id": "Ra20kIYBD3T716opayt9", "_score": 1, "_source": { "id": "2", "name": "李四", "avatar": "https://profile-avatar.csdnimg.cn/21f4a00156854dcab8a86032bf5b9068_weixin_43844718.jpg!0", "age": 22 } } ] } }
官方提供 Update API
实际上是局部更新,能够编写文档更新脚本。要完全替换现有文档,则使用 索引文档API
。
更新API支持传递合并到现有文档中的部分文档。
更新API 还能够编写文档更新脚本,脚本可以更新、删除或跳过修改文档。
语法:
POST /<index>/_update/<_id>
路径参数:
<index>
(必需,字符串)包含文档的索引的名称。
<_id>
(必需,字符串)文档的唯一标识符。
请求体:
doc:修改信息。
script:脚本内容。
测试:
修改源数据: //请求: POST /test/_update/1 { "doc": { "name":"张三222", "age":30 } } //返回: { "_index": "test", "_id": "1", "_version": 2, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 3, "_primary_term": 1 } //请求: GET test/_source/1 //返回: { "id": "1", "name": "张三222", "avatar": "https://profile-avatar.csdnimg.cn/21f4a00156854dcab8a86032bf5b9068_weixin_43844718.jpg!0", "age": 30 } 执行脚本测试(年龄加10): //请求: POST test/_update/1 { "script" : { "source": "ctx._source.age+= params.add", "lang": "painless", "params" : { "add" : 10 } } } //返回: { "_index": "test", "_id": "1", "_version": 3, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 4, "_primary_term": 1 } //请求: GET test/_source/1 //返回: { "id": "1", "name": "张三222", "avatar": "https://profile-avatar.csdnimg.cn/21f4a00156854dcab8a86032bf5b9068_weixin_43844718.jpg!0", "age": 40 }
和新增文档一样,如果请求体变化,会将原有的数据内容覆盖。
测试:
//请求: POST test/_doc/1 { "name":"李四" } //返回: { "_index": "test", "_id": "1", "_version": 4, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 10, "_primary_term": 1 }
DELETE /<index>/_doc/<_id>
测试:
//请求: DELETE test/_doc/1 //返回: { "_index": "test", "_id": "1", "_version": 10, "result": "deleted", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 11, "_primary_term": 1 } //请求: GET test/_doc/1 //返回: { "_index": "test", "_id": "1", "found": false }
Search API 执行搜索查询并返回与查询匹配的搜索命中。可以使用 查询字符串参数
或 请求体
提供搜索查询。
GET /<target>/_search GET /_search POST /<target>/_search POST /_search 路径参数: <target> (可选,字符串)以逗号分隔的数据流、索引和别名列表 搜索。支持通配符 ()。省略则搜索所有数据流和索引。 部分查询参数(更多参考: https://www.elastic.co/guide/en/elasticsearch/reference/8.6/search-search.html): q: (可选,字符串)使用Lucene查询字符串语法进行查询。您可以使用q参数来运行查询参数搜索。查询参数搜索不支持完整的Elasticsearch查询DSL,但便于测试。 from: (可选,整数)起始文档偏移量。需要为非负,默认值为0。默认情况下,使用from和size参数,页面浏览次数不能超过10000次。要浏览更多点击,请使用search_after参数。 size: (可选,整数)定义要返回的命中数。默认值为 10。默认情况下,使用from和size参数,页面浏览次数不能超过10000次。要浏览更多点击,请使用search_after参数。 sort: (可选,字符串)以逗号分隔的<field>:<direction>对列表。 _source: (可选) (可选)指示为匹配的文档返回哪些源字段。这些字段在命中时返回_搜索响应的源属性。默认为true。请参见源过滤。 true:(布尔值)返回整个文档源。 false:(布尔值)不返回文档源。 <string>:(string)要返回的源字段的逗号分隔列表。支持通配符(*)模式。 timeout: (可选,时间单位)指定等待每个碎片响应的时间段。如果在超时到期之前没有收到响应,则请求失败并返回错误。默认为无超时。 version: (可选,布尔值)如果为true,则返回文档版本作为命中的一部分。默认为false。
先准备下数据:
GET test/_search { "took": 0, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 3, "relation": "eq" }, "max_score": 1, "hits": [ { "_index": "test", "_id": "1", "_score": 1, "_source": { "id": "1", "name": "张三", "age": 25, "address": "江苏省苏州市苏州工业园区" } }, { "_index": "test", "_id": "2", "_score": 1, "_source": { "id": "2", "name": "李四", "age": 22, "address": "上海市浦东新区锦绣路1001号世纪公园" } }, { "_index": "test", "_id": "3", "_score": 1, "_source": { "id": "3", "name": "王五", "age": 30, "address": "江苏省南通市崇川区兴通路98-99号南通国际会展中心" } } ] } }
Query参数查询 测试:
//请求: GET test/_search?q=name:张三 //返回: { "took": 411, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 1, "relation": "eq" }, "max_score": 1.9616582, "hits": [ { "_index": "test", "_id": "1", "_score": 1.9616582, "_source": { "id": "1", "name": "张三", "age": 25, "address": "江苏省苏州市苏州工业园区" } } ] } } //请求: GET test/_search?q=name:张三&from=0&size=2&_source=name //返回: { "took": 0, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 1, "relation": "eq" }, "max_score": 1.9616582, "hits": [ { "_index": "test", "_id": "1", "_score": 1.9616582, "_source": { "name": "张三" # _source 限制返回字段 } } ] } }
请求体查询 测试:
//请求: GET test/_search { "query": { "match": { "name": "张三" } }, "from": 0, "size": 2, "_source": ["name", "address"], "sort": [ { "id": { "order": "desc" } } ] } //返回: { "took": 0, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 1, "relation": "eq" }, "max_score": null, "hits": [ { "_index": "test", "_id": "1", "_score": null, "_source": { "name": "张三", "address": "江苏省苏州市苏州工业园区" }, "sort": [ 1 ] } ] } }
match_all
:等同于上面的空查询,没有任何条件,最简单的查询,它匹配所有文档就相当于空搜索,给它们的_score 默认都是1.0,可以通过boost 设置,可以进行一些排序之类的。
//请求: GET test/_search { "query":{ "match_all":{} } } //返回: { "took": 0, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 3, "relation": "eq" }, "max_score": 1, "hits": [ { "_index": "test", "_id": "1", "_score": 1, "_source": { "id": 1, "name": "张三", "age": 25, "address": "江苏省苏州市苏州工业园区" } }, { "_index": "test", "_id": "2", "_score": 1, "_source": { "id": 2, "name": "李四", "age": 22, "address": "上海市浦东新区锦绣路1001号世纪公园" } }, { "_index": "test", "_id": "3", "_score": 1, "_source": { "id": 3, "name": "王五", "age": 3, "address": "江苏省南通市崇川区兴通路98-99号南通国际会展中心" } } ] } }
下面示例都使用请求体测试。
首先我们需要知道 ES 中默认使用分词器为 标准分词器(StandardAnalyzer)
,标准分词器对于英文 单词分词
,对于中文 单字分词
。
在 ES 的 映射类型(Mapping Type) 中 keyword
,date
,integer
,long
,double
,boolean
or ip
这些类型不分词,只有 text
类型分词。
match
:先对搜索词进行分词,分词完毕后再逐个对分词结果进行匹配,因此相比于 term
的精确搜索,match
是分词匹配搜索,相当于模糊匹配,只包含其中一部分关键词就行 。
注意:这里的
match
和 下面的match_pharse
查询都是属于全文查询
,全文查询会给当前的句子进行分词,通常来讲,索引的时候怎么分的词,查询的时候就是用的什么分词器,默认是不用设置的,但是如果有个别场景,也可以自己设置分词器。
//请求: GET test/_search { "query": { "match": { "address": "江南" # 匹配江南,搜索到包含江苏和南通的两条数据 } } } //返回: { "took": 0, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 2, "relation": "eq" }, "max_score": 1.6375607, "hits": [ { "_index": "test", "_id": "3", "_score": 1.6375607, "_source": { "id": 3, "name": "王五", "age": 3, "address": "江苏省南通市崇川区兴通路98-99号南通国际会展中心" } }, { "_index": "test", "_id": "1", "_score": 0.53428984, "_source": { "id": 1, "name": "张三", "age": 25, "address": "江苏省苏州市苏州工业园区" } } ] } }
模糊查询:
在实际的搜索中,我们有时候会打错字,从而导致搜索不到。在 ES 中,我们可以使用 fuzziness
属性 设置 编辑距离
来进行模糊查询,从而达到搜索有错别字的情形。
match
查询具有 fuziness
属性。它可以被设置为 0
, 1
, 2
或 auto
。auto
是推荐的选项,它会根据查询词的长度定义距离。在实际的使用中,当我们使用 auto
时,如果字符串的长度大于5,那么 funziness
的值自动设置为2,如果字符串的长度小于2,那么 fuziness
的值自动设置为 0。
编辑距离
是将一个术语转换为另一个术语所需的一个字符更改的次数。 这些更改可以包括:
准备数据:
POST /test/_update/1
{
"doc": {
"hobby": "football, basketball" # 使用英文测试,中文是分析器处理后是单字,英文是多个字母,更适合测试
}
}
测试:
//请求: GET /test/_search { "query": { "match": { "hobby": "footbalf" # 当只有一个字母不同,正常匹配搜索不到 } } } //返回: { "took": 0, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 0, "relation": "eq" }, "max_score": null, "hits": [] } } //请求: GET /test/_search { "query": { "match": { "hobby": { "query": "footbalf", "fuzziness": "1" # 编辑距离为 1,football 和 footbalf 只有一个字母不同,这时就可以搜索到。 } } } } //返回: { "took": 1, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 1, "relation": "eq" }, "max_score": 0.25172183, "hits": [ { "_index": "test", "_id": "1", "_score": 0.25172183, "_source": { "id": 1, "name": "张三222", "age": 25, "address": "江苏省苏州市苏州工业园区", "time": "2021/01/01", "hobby": "football, basketball" } } ] } }
fuziness
设置是针对每个词语而言的,而不是总的错误的数值,所以可以查询多个单词。
//请求: GET /test/_search { "query": { "match": { "hobby": { "query": "footbalf basketbalf", "fuzziness": "1" } } } } //返回: { "took": 11, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 1, "relation": "eq" }, "max_score": 0.51063573, "hits": [ { "_index": "test", "_id": "1", "_score": 0.51063573, "_source": { "id": 1, "name": "张三222", "age": 25, "address": "江苏省苏州市苏州工业园区", "time": "2021/01/01", "hobby": "football, basketball" } } ] } }
ES 的 fuzzy 查询
,功能和上面一样,但是这个只针对一个 term 比较有用。
//请求: GET /test/_search { "query": { "fuzzy": { "hobby": { "value": "footbalf", "fuzziness": "1" } } } } //返回: { "took": 0, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 1, "relation": "eq" }, "max_score": 0.25172183, "hits": [ { "_index": "test", "_id": "1", "_score": 0.25172183, "_source": { "id": 1, "name": "张三222", "age": 25, "address": "江苏省苏州市苏州工业园区", "time": "2021/01/01", "hobby": "football, basketball" } } ] } } //请求: GET /test/_search { "query": { "fuzzy": { "hobby": { "value": "footbalf basketbal", # 两个单词就查询不到了 "fuzziness": "1" } } } } //返回: { "took": 1, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 0, "relation": "eq" }, "max_score": null, "hits": [] } }
参考:
Elasticsearch:fuzzy 搜索 (模糊搜索)
ES 8.x Doc - 模糊查询
match_phrase
:短语匹配查询,要求必须全部精确匹配,且顺序必须与指定的短语相同。首先解析查询字符串来产生一个词条列表,然后会搜索所有的词条,但只保留包含了所有搜索词条的文档。match_phrase 还支持词条列表各词项间隔距离多少的设置。
//请求: GET test/_search { "query":{ "match_phrase": { "address": "江南" # 未匹配到江南,三条数据地址有包含江苏或南通,但是没有江南 } } } //返回: { "took": 0, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 0, "relation": "eq" }, "max_score": null, "hits": [] } }
term
:单词或单字精确匹配,只是查分词,不会对查询语句进行分词,所以会区分大小写。
terms
:多个 term 的并集。
注意: term查询是基于词项的查询,当使用 term查询时,ES 不会对这个词做任何处理,但是在文本进行分词时,通常都会将大写转为小写,这个时候就会出现查不出来的情况。
//请求: GET test/_search { "query":{ "term": { "address": { "value": "江" # 匹配包含江字的数据,两条 } } } } //返回: { "took": 0, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 2, "relation": "eq" }, "max_score": 0.53428984, "hits": [ { "_index": "test", "_id": "1", "_score": 0.53428984, "_source": { "id": 1, "name": "张三", "age": 25, "address": "江苏省苏州市苏州工业园区" } }, { "_index": "test", "_id": "3", "_score": 0.41070414, "_source": { "id": 3, "name": "王五", "age": 3, "address": "江苏省南通市崇川区兴通路98-99号南通国际会展中心" } } ] } } //请求: GET test/_search { "query":{ "terms": { "address": ["江","南"] # terms 就相当于多个 term 的并集 } } } //返回: { "took": 1, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 2, "relation": "eq" }, "max_score": 1, "hits": [ { "_index": "test", "_id": "1", "_score": 1, "_source": { "id": 1, "name": "张三", "age": 25, "address": "江苏省苏州市苏州工业园区" } }, { "_index": "test", "_id": "3", "_score": 1, "_source": { "id": 3, "name": "王五", "age": 3, "address": "江苏省南通市崇川区兴通路98-99号南通国际会展中心" } } ] } }
multi_match
查询提供了一个简便的方法用来对多个字段执行相同的查询。
更改一下数据:
POST /test/_update/2
{
"doc": {
"address": "上海市浦东新区锦绣路1001号世纪公园张三家旁边"
}
}
测试:
//请求: GET /test/_search { "query": { "multi_match": { "query": "张三", "fields": ["name","address"] } } } //返回: { "took": 718, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 2, "relation": "eq" }, "max_score": 2.5153382, "hits": [ { "_index": "test", "_id": "2", "_score": 2.5153382, "_source": { "id": 2, "name": "李四", "age": 22, "address": "上海市浦东新区锦绣路1001号世纪公园张三家旁边", "time": "2022/01/01" } }, { "_index": "test", "_id": "1", "_score": 1.5241971, "_source": { "id": 1, "name": "张三222", "age": 25, "address": "江苏省苏州市苏州工业园区", "time": "2021/01/01", "hobby": "football, basketball" } } ] } }
prefix
:查询返回在提供的字段中包含特定前缀的文档。
前缀匹配只适用于 keyword
,是不做分词的且大小写敏感, 因为前缀匹配不涉及索引分词,所以只能匹配 关键字 keyword
,因此效率很低,不推荐生产环境使用。
//请求: GET /test/_search { "query": { "prefix": { "address.keyword": "上海" # } } } //返回: { "took": 0, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 1, "relation": "eq" }, "max_score": 1, "hits": [ { "_index": "test", "_id": "2", "_score": 1, "_source": { "id": 2, "name": "李四", "age": 22, "address": "上海市浦东新区锦绣路1001号世纪公园张三家旁边", "time": "2022/01/01" } } ] } }
参考:【ElasticSearch】ElasticSearch中字符串.keyword和.text类型区别和模糊查询
wildcard
:ES中可以实现通配符搜索,通配符匹配也是扫描完整索引,通配符可以在 索引中使用,也可以在 keyword中使用。
ElsticSearch支持的通配符有2个,分别是:
*
:0个或多个任意字符?
:任意单个字符注意: 为了防止极慢的通配符匹配,查询字符串不要以通配符开头,只在查询字符串中间或末尾使用通配符。
//请求: GET /test/_search { "query": { "wildcard": { "address.keyword": { # 如果是address 的话只能匹配 单字 才有数据 "value": "上海*" } } } } //返回: { "took": 0, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 1, "relation": "eq" }, "max_score": 1, "hits": [ { "_index": "test", "_id": "2", "_score": 1, "_source": { "id": 2, "name": "李四", "age": 22, "address": "上海市浦东新区锦绣路1001号世纪公园张三家旁边", "time": "2022/01/01" } } ] } }
range 查询可同时提供包含(inclusive)和不包含(exclusive)这两种范围表达式,可供组合的选项如下:
gt: > 大于(greater than)
lt: < 小于(less than)
gte: >= 大于或等于(greater than or equal to)
lte: <= 小于或等于(less than or equal to)
//请求: GET test/_search { "query":{ "range": { "age": { # 查询年龄在 10~20 之间的数据 "gte": 10, "lte": 22 } } } } //返回: { "took": 0, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 1, "relation": "eq" }, "max_score": 1, "hits": [ { "_index": "test", "_id": "2", "_score": 1, "_source": { "id": 2, "name": "李四", "age": 22, "address": "上海市浦东新区锦绣路1001号世纪公园" } } ] } }
添加下时间 time
:
POST /test/_update/1 { "doc": { "time":"2021/01/01" } } POST /test/_update/2 { "doc": { "time":"2022/01/01" } } POST /test/_update/3 { "doc": { "time": "2023/01/01" } }
range
查询同样可以应用在日期字段上:
//请求: GET test/_search { "query":{ "range": { "time": { "gt": "2022/03/01", "lt": "2023/03/01" } } } } //返回: { "took": 0, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 1, "relation": "eq" }, "max_score": 1, "hits": [ { "_index": "test", "_id": "3", "_score": 1, "_source": { "id": 3, "name": "王五", "age": 3, "address": "江苏省南通市崇川区兴通路98-99号南通国际会展中心", "time": "2023/01/01" } } ] } }
根据 ID 返回文档。此查询使用存储在 _id 字段中的文档 ID。
请求参数:
ids.values:(必填, 字符串数组) 文档的_id的数组
//请求: GET /test/_search { "query": { "ids": { "values": ["1","2"] } } } //返回: { "took": 23, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 2, "relation": "eq" }, "max_score": 1, "hits": [ { "_index": "test", "_id": "2", "_score": 1, "_source": { "id": 2, "name": "李四", "age": 22, "address": "上海市浦东新区锦绣路1001号世纪公园", "time": "2022/01/01" } }, { "_index": "test", "_id": "1", "_score": 1, "_source": { "id": 1, "name": "张三222", "age": 25, "address": "江苏省苏州市苏州工业园区", "time": "2021/01/01" } } ] } }
现实的查询需求从来都没有那么简单;它们需要在多个字段上查询多种多样的文本,并且根据一系列的标准来过滤。为了构建类似的高级查询,你需要一种能够将多查询组合成单一查询的查询方法。
bool 查询
:可以实现你的需求。这种查询将多查询组合在一起,成为用户自己想要的布尔查询。它接收以下参数:
must
:文档 必须 匹配这些条件才能被包含进来。must_not
:文档 必须不 匹配这些条件才能被包含进来。should
:如果满足这些语句中的任意语句,将增加 _score
,否则,无任何影响。它们主要用于修正每个文档的相关性得分。filter
:必须 匹配,但它以不评分、过滤模式来进行。这些语句对评分没有贡献,只是根据过滤标准来排除或包含文档。Filter Context 和 Query Context 的区别:
- 进行query context查询时,ES除了要判断某个文档是否与查询值匹配,还要计算相关度评分(relevance score),并放入到返回结果的_score字段中!
- 而当进行filter context查询时,仅仅判断某个文档是否与查询值匹配,不但无需进行相关度评分的计算,而且对于高频率的filter查询,ES还会自动将查询结果缓存起来,以提高filter查询的性能。
must
和should
属于Query Context
,会对_score
结果产生影响;
filter
和must_not
属于Filter Context
,不会对_score
结果产生影响;
测试:
//请求: GET /test/_search { "query": { "bool": { "must": [ { "match": { "name": "张三" }} # name 包含张三 ], "must_not": [ { "match": { "address": "上海" }} # 地址不能包含 上海 ], "should": [ { "term": { "hobby": "football" }} # 匹配到的数据中包含 football,_score 增加,未匹配到 _score 不变 ], "filter": [ { "range": { "age": { "gte": "20" }}} # 过滤,筛选 age 大于等于 20 的数据 ] } } } //返回: { "took": 1, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 1, "relation": "eq" }, "max_score": 2.0440507, "hits": [ { "_index": "test", "_id": "1", "_score": 2.0440507, "_source": { "id": 1, "name": "张三222", "age": 25, "address": "江苏省苏州市苏州工业园区", "time": "2021/01/01", "hobby": "football, basketball" } } ] } }
参考:
ES - query-filter-context
Elasticsearch: 权威指南 - 组合多查询
_source
:指定返回的源数据字段。
//请求: GET test/_search { "_source": ["name"] } //返回: { "took": 0, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 3, "relation": "eq" }, "max_score": 1, "hits": [ { "_index": "test", "_id": "3", "_score": 1, "_source": { "name": "王五" } }, { "_index": "test", "_id": "2", "_score": 1, "_source": { "name": "李四" } }, { "_index": "test", "_id": "1", "_score": 1, "_source": { "name": "张三" } } ] } }
如果返回的结果集中很多符合条件的结果,那怎么能一眼就能看到我们想要的那个结果呢?比如像百度所示的那样,将搜索词高亮显示:
如果要达到上图的效果怎么做呢,ES 提供了 高亮查询 API 可以高亮显示搜索信息:
highlight
:ES 会从查询到的数据中,找到匹配的短语或关键字词,并以 <em></em>
标签包裹起来。
//请求: GET /test/_search { "query": { "match": { "address": "江南" } }, "highlight": { "fields": { "address": {} } } } //返回: { "took": 2, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 2, "relation": "eq" }, "max_score": 1.7658587, "hits": [ { "_index": "test", "_id": "3", "_score": 1.7658587, "_source": { "id": 3, "name": "王五", "age": 3, "address": "江苏省南通市崇川区兴通路98-99号南通国际会展中心", "time": "2023/01/01" }, "highlight": { "address": [ "<em>江</em>苏省<em>南</em>通市崇川区兴通路98-99号<em>南</em>通国际会展中心" ] } }, { "_index": "test", "_id": "1", "_score": 0.395165, "_source": { "id": 1, "name": "张三222", "age": 25, "address": "江苏省苏州市苏州工业园区", "time": "2021/01/01" }, "highlight": { "address": [ "<em>江</em>苏省苏州市苏州工业园区" ] } } ] } }
ES 可以在 highlight
中使用 pre_tags
和 post_tags
来自定义匹配内容前后高亮的html标签 。
//请求: GET /test/_search { "query": { "match": { "address": "江南" } }, "highlight": { "pre_tags": "<b style='color:red'>", "post_tags": "</b>", "fields": { "address": {} } } } //返回: { "took": 1, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 2, "relation": "eq" }, "max_score": 1.7658587, "hits": [ { "_index": "test", "_id": "3", "_score": 1.7658587, "_source": { "id": 3, "name": "王五", "age": 3, "address": "江苏省南通市崇川区兴通路98-99号南通国际会展中心", "time": "2023/01/01" }, "highlight": { "address": [ "<b style='color:red'>江</b>苏省<b style='color:red'>南</b>通市崇川区兴通路98-99号<b style='color:red'>南</b>通国际会展中心" ] } }, { "_index": "test", "_id": "1", "_score": 0.395165, "_source": { "id": 1, "name": "张三222", "age": 25, "address": "江苏省苏州市苏州工业园区", "time": "2021/01/01" }, "highlight": { "address": [ "<b style='color:red'>江</b>苏省苏州市苏州工业园区" ] } } ] } }
sort
:指定字段排序方式。
数据模型的复杂程度决定了排序的复杂程度,排序的复杂程度随着模型的复杂程度成指数级增加。这里就简单的介绍普通用法。
//请求: GET test/_search { "sort": { "id": { "order": "asc" } } } //返回: { "took": 0, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 3, "relation": "eq" }, "max_score": null, "hits": [ { "_index": "test", "_id": "1", "_score": null, "_source": { "id": 1, "name": "张三", "age": 25, "address": "江苏省苏州市苏州工业园区", "time": "2021/01/01" }, "sort": [ 1 ] }, { "_index": "test", "_id": "2", "_score": null, "_source": { "id": 2, "name": "李四", "age": 22, "address": "上海市浦东新区锦绣路1001号世纪公园", "time": "2022/01/01" }, "sort": [ 2 ] }, { "_index": "test", "_id": "3", "_score": null, "_source": { "id": 3, "name": "王五", "age": 3, "address": "江苏省南通市崇川区兴通路98-99号南通国际会展中心", "time": "2023/01/01" }, "sort": [ 3 ] } ] } }
from
:起始数据位置。
size
:返回数据数量。
ES 分页查询限制总数能不超过10000,原因是基本用不到10000条以后数据,如果前面10000条数据还没有找到你想要的数据,那么后面的匹配度更低,找到的概率更小,查询速度也会越来越慢,合理没必要查10000以后的。
//请求: GET test/_search { "from": 0, # 0 开始 "size": 2 # 获取两条数据 } //返回: { "took": 0, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 3, # 总数3 "relation": "eq" }, "max_score": 1, "hits": [ { "_index": "test", "_id": "3", "_score": 1, "_source": { "id": 3, "name": "王五", "age": 3, "address": "江苏省南通市崇川区兴通路98-99号南通国际会展中心", "time": "2023/01/01" } }, { "_index": "test", "_id": "2", "_score": 1, "_source": { "id": 2, "name": "李四", "age": 22, "address": "上海市浦东新区锦绣路1001号世纪公园", "time": "2022/01/01" } } ] } }
批量操作的好处在于可以一次请求完成多次操作,不需要发送多次,可以解决很多网络的开销,可以显著的提高索引的速度。
_mget
:可以同时执行不同的 get 操作,多个API操作之间的结果互不影响。
//请求: GET /test/_mget { "docs":[ { "_id": 1 }, { "_id": 2 } ] } 都是根据id,查询的话,也可以使用下面 ids 这种写法,结果一样: GET /test/_mget { "ids": [1,2] } //返回: { "docs": [ { "_index": "test", "_id": "1", "_version": 2, "_seq_no": 5, "_primary_term": 1, "found": true, "_source": { "id": 1, "name": "张三", "age": 25, "address": "江苏省苏州市苏州工业园区", "time": "2021/01/01" } }, { "_index": "test", "_id": "2", "_version": 2, "_seq_no": 4, "_primary_term": 1, "found": true, "_source": { "id": 2, "name": "李四", "age": 22, "address": "上海市浦东新区锦绣路1001号世纪公园", "time": "2022/01/01" } } ] }
创建索引 test2,添加一条数据:
POST test2/_doc/1
{
"id":1,
"name":"赵六",
"age":30,
"address": "杭州市上城区万松岭路81号"
}
//请求: GET /_mget { "docs":[ { "_index":"test", # ES 8.x 以后不需要 _type "_id": 1 }, { "_index":"test2", "_id": 1 } ] } //返回: { "docs": [ { "_index": "test", "_id": "1", "_version": 2, "_seq_no": 5, "_primary_term": 1, "found": true, "_source": { "id": 1, "name": "张三", "age": 25, "address": "江苏省苏州市苏州工业园区", "time": "2021/01/01" } }, { "_index": "test2", "_id": "1", "_version": 1, "_seq_no": 0, "_primary_term": 1, "found": true, "_source": { "id": 1, "name": "赵六", "age": 30, "address": "杭州市上城区万松岭路81号" } } ] }
_bulk
:可以同时执行不同的CUD操作,多个API操作之间的结果互不影响。
bulk request
会加载到内存中,如果太大的话,性能反而下降,因此需要反复尝试一个最大的 bulk size
。一般从1000~5000条数据开始,尝试逐渐增加。另外,如果看大小的话,最好在5M。
注意:bulk操作不能进行代码换行。
POST /_bulk
{action1:{metadata1}}
{requestbody1}
{action2:{metadata2}}
{requestbody2}
测试:
//请求: POST /_bulk {"index":{"_index":"test3","_id":1}} {"doc":{"id":1,"name":"孙七","age":50,"address":"地球"}} {"create":{"_index":"member","_id":999}} {"doc":{"id":1,"name":"周八","age":80,"address":"地球2"}} {"delete":{"_index":"test2","_id":"1"}} {"update":{"_index":"test","_id":1}} {"doc":{"name":"张三222"}} //返回: { "took": 471, "errors": false, "items": [ { "index": { "_index": "test3", "_id": "1", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 0, "_primary_term": 1, "status": 201 } }, { "create": { "_index": "member", "_id": "999", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 0, "_primary_term": 1, "status": 201 } }, { "delete": { "_index": "test2", "_id": "1", "_version": 2, "result": "deleted", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 1, "_primary_term": 1, "status": 200 } }, { "update": { "_index": "test", "_id": "1", "_version": 3, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 6, "_primary_term": 1, "status": 200 } } ] }
elastic 官网 访问缓慢已常态,还经常无法访问,为了方便看文档,我使用 DownGit 从 GitHub 下载了离线文档,但是下载的离线文档没有左侧API导航栏这个比较坑。
还有一点是关于翻译的问题,ES 的中文版版本太低,我们常用的还是英文版,谷歌的翻译功能又不可用,想要翻译成中文可以使用 Edge 浏览器。
下载离线文档参考:
DownGit
GitHub ES 8.6 文档地址(也可选择其他版本)
GitHub ES 8.6 文档样式渲染地址
Elasticsearch进阶教程:生成离线官方文档
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。