ElasticSearch官网 开启搜索的新境界
Elasticsearch 是一个开源的搜索引擎,建立在一个全文搜索引擎库 Apache Lucene™ 基础之上。 Lucene 可以说是当下最先进、高性能、全功能的搜索引擎库。但是 Lucene 仅仅只是一个库。为了充分发挥其功能,你需要使用 Java 并将 Lucene 直接集成到应用程序中。 更糟糕的是,您可能需要获得信息检索学位才能了解其工作原理。Lucene 非常复杂。Elasticsearch 也是使用 Java 编写的,它的内部使用 Lucene 做索引与搜索,但是它的目的是使全文检索变得简单, 通过隐藏 Lucene 的复杂性,取而代之的提供一套简单一致的 RESTful API。
Elasticsearch 不仅仅是 Lucene,并且也不仅仅只是一个全文搜索引擎。 它可以被下面这样准确的形容:
Elasticsearch将所有的功能打包成一个单独的服务,这样你可以通过程序与它提供的简单的 RESTful API 进行通信, 可以使用自己喜欢的编程语言充当 web 客户端,甚至可以使用命令行去充当这个客户端。
Kibana官网
Kibana是一个针对Elasticsearch的开源分析及可视化平台,用来搜索、查看交互存储在Elasticsearch索引中的数据。使用Kibana,可以通过各种图表进行高级数据分析及展示。Kibana让海量数据更容易理解。它操作简单,基于浏览器的用户界面。可以快速创建仪表板、实时显示Elasticsearch查询动态。
Relational DB | ElasticSearch |
---|---|
database | index |
tables | types |
rows | documents |
columns | fields |
schema | mapping |
Innodb | Lucene |
elasticsearch把每个索引划分成多个分片,每个分片可以在集群中的不同服务器间迁移。默认的集群名elasticsearch,docker中默认的集群为docker-cluster。
一个索引包含多个文档,而索引存储在分片当中。当我们索引一篇文档时可以通过索引-类型-文档ID的顺序找到文档。
elasticsearch是面向文档的,那么就意味着索引和搜索数据的最小单位是文档
类型是文档的逻辑容器,就像关系型数据库一样,表格是行的容器。类型中对于字段的定义称为映射,比如name映射为字符串类型。文档是无模式的,不需要拥有映射中所定义的所有字段,比如新增一个字段,ES会自动的将新字段加入映射,但是这个字段的不确定它是什么类型,ES就开始猜,如果这个值是一个数,那么ES会认为它是整形。但是ES也可能猜不对,所以最安全的方式就是提前定义好所需要的映射,然后再使用。
索引即数据库,是映射类型的容器,elasticsearch中的索引是一个非常大的文档集合。索引存储了映射类型的字段和其他设置。然后它们被存储到了各个分片上了。
一个集群至少有一个节点,而一个节点就是一个ES进程,节点可以有多个索引,如果你创建索引,那么索引将会由5个分片(primary shard)构成,每一个主分片会有一个副本(replica shard)
上图是一个有3个节点的集群,可以看到主分片和对应的复制分片都不会在同一个节点内,这样有利于某个节点挂掉了,数据也不至于丢失。实际上,一个分片是一个Lucene索引,一个包含倒排索引的文件目录,倒排索引的结构使得elasticsearch在不扫描全部文档的情况下,就能告诉你哪些文档包含特定的关键字。
索引存在的意义就是为了加快数据的查询。在关系型数据库中如果没有索引的话,为了查找数据我们需要每条数据去进行比对,运气不好的话可能需要扫描全表才能查找到想要的数据。以Mysql为例,它使用了B+树作为索引来加速数据的查询。
所谓正排索引就像书中的目录一样,根据页码查询内容,但是倒排索引确实相反的,它是通过对内容的分词,建立内容到文档ID的关联关系。这样在进行全文检索的时候,根据词典的内容便可以精确以及模糊查询,非常符合全文检索的要求。
倒排索引的结构主要包括了两大部分一个是Term Dictionary,另一个是Posting List。Term Dictionary记录了所用文档的单词以及单词和倒排列表的关系。Posting List则是记录了term在文档中的位置以及其他信息,主要包括文档ID,词频(term在文档中出现的次数,用来计算相关性评分),位置以及偏移。
一种软件架构风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
method | url地址 | 描述 |
---|---|---|
PUT | localhost:9200/索引名称/类型名称/文档id | 创建文档(指定文档id) |
POST | localhost:9200/索引名称/类型名称 | 创建文档(随机文档id) |
POST | localhost:9200/索引名称/类型名称/文档id/_update | 修改文档 |
DELETE | localhost:9200/索引名称/类型名称/文档id | 删除文档 |
GET | localhost:9200/索引名称/类型名称/文档id | 查询文档通过文档id |
POST | localhost:9200/索引名称/类型名称/_search | 查询所有数据 |
docker + elasticsearch7.6 + kibana7.6
# 注意 elasticsearch和kibana版本要一致
docker pull elasticsearch:7.6.0
docker pull kibana:7.6.0
# 启动elasticsearch
# --name 指定容器的名称
# -e 指定环境变量,容器中可以使用该环境变量。
# ES_JAVA_OPTS 代表设定ES的最大与最小的heap
# discovery.type 设置发现类型
docker run -d --name es -p 9200:9200 -p 9300:9300 -e ES_JAVA_OPTS="-Xms512m -Xmx512m" -e "discovery.type=single-node" elasticsearch:7.6.0
# 启动kibana
docker run -d --name=kibana -p 5601:5601 kibana:7.6.0
# 进入kibana容器 修改config
docker exec -it CONTAINER-ID bash
vi /config/kibana.yml
# 修改elasticsearch.hosts参数
# 将array中的ip修改为你的es的ip地址
# 汉化 添加i18n.locale
i18n.locale: "zh-CN"
# 修改完成保存
# 重启容器
docker restart KIBANA-CONTAINER-ID
在创建文档时,ES会根据字段的值动态的推断出它的类型,即动态映射,但这样可能出现推断不符合预期的问题,例如日期类型,所以我们需要根据实际情况选择是否主动指定字段的类型。
当一个字段的内容需要被全文检索时,可以使用text类型,支持长内容的存储,比如检索文章内容、商品信息等。该类型的字段内容在保存时会被分词器分析,并且拆分成多个词项, 然后根据拆分后的词项生成对应的索引,根据关键字检索时可能会将关键字分词,用分好的词从之前生成的索引中去匹配,进而找到对应的文档。对于text类型的字段无法通过指定文本精确的检索到。text类型的字段不能直接用于排序、聚合操作。这种类型的字符串也称做analyzed字符串。
keyword类型适用于结构化的字段,比如手机号、商品id等,默认最大长度为256。keyword类型的字段内容不会被分词器分析、拆分,而是根据原始文本直接生成倒排索引,所以keyword类型的字段可以直接通过原始文本精确的检索到。keyword类型的字段可用于过滤、排序、聚合操作。这种字符串称做not-analyzed字符串。
ES 中的date类型默认支持如下两种格式
如果我们要存储类似2020-12-01 20:10:15这种格式的日期就会有问题,我们可以在创建索引时指定字段为date类型以及可以匹配的日期格式:
PUT /info
{
"mappings": {
"properties": {
"publishDate":{
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
}
}
}
需要注意的是,如果不主动指定字段类型为date,ES 默认使用text类型去保存日期的值。
boolean类型true、false两个值
类型 | 取值范围 |
---|---|
byte | -2^7 ~ 2^7-1 |
short | -2^15 ~ 2^15-1 |
integer | -2^31 ~ 2^31-1 |
long | -2^63 ~ 2^63-1 |
float | 32位单精度IEEE 754浮点类型 |
double | 64位双精度IEEE 754浮点类型 |
half_float | 16位半精度IEEE 754浮点类型 |
scaled_float | 缩放类型的的浮点数 |
一般情况下,如果可以满足需求,则优先使用范围小的类型,来提高效率。
在 ES 中并没有数组类型,但我们却可以按数组格式来存储数据,因为 ES 中默认每个字段可以包含多个值,同时要求多个值得类型必须一致。例如可以按照如下方式指定一个字段的值为数组:
"label": [
"ElastcSearch",
"7.6.0版本"
]
由于 ES 中以 JSON 格式存储数据,所以一个JSON对象中的某个字段值可以是另一个JSON对象。
类型 | 技能 |
---|---|
integer_range | -2^31 ~ 2^31-1 |
long_range | -2^63 ~ 2^63-1 |
float_range | 32位单精度IEEE 754浮点类型 |
double_range | 64位双精度IEEE 754浮点类型 |
date_range | 自系统历元以来无符号64位整数范围内的毫秒数 |
ip_range | IPv4、IPv6 的一系列IP地址值 |
例如可以创建索引时定义一个日期范围的字段类型
PUT /test
{
"mappings": {
"properties": {
"reader_num":{
"type": "integer_range"
}
}
}
}
添加文档时指定字段的值
"reader_age_range": {
"gte": 10,
"lte": 50
}
参数v会返回带有标题的更全面的信息
在查询字符串中增加pretty参数,会让Elasticsearch美化输出JSON响应以便更加容易阅读
GET /_cat/nodes?v
GET _cat/health?v
GET /_cat/indices?v
GET _cat/templates
# 查看全部
GET /_cat/shards?v
# 查看指定索引
GET /_cat/shards/<index>?v
GET /_cat/plugins?v
GET /_cat/indices?v
# 按索引占用内存大小
GET /_cat/indices?v&h=i,tm&s=tm:desc
# 按文档数量排序索引
GET /_cat/indices?v&s=docs.count:desc
# 根据健康状态查询索引 green/yellow/red
GET /_cat/indices?v&health=green
# 查看所有索引文档总数
GET /_all/_count
# 查看指定索引文档总数
GET /<index>/_count
GET /_cat/shards/<index>?v
# mappings和settings信息
GET /<index>
# 查看mapping
GET test/_mapping?pretty
DELETE /<index>
# 指定索引分片和副本数量
PUT /<index>
{
"settings": {
"number_of_shards": 2, # 分片
"number_of_replicas": 2 # 副本
}
}
# 指定分片数量与mapping映射
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"field1":{
"type": "type2"
},
"field2":{
"type": "type2"
}
}
}
}
PUT /_settings
{
"index": {
"number_of_replicas": 2
}
}
POST //_mapping
{
"properties": {
"field":{
"type": "type"
}
}
}
POST和PUT请求都可以新增文档,区别在于PUT创建文档必须指定Id,而POST可以指定也可以不指定,不指定ID则会随机生成一个Id。关于mapping:
# 指定文档Id
POST /<index>/_doc/<Id>
{
"key":"value"
}
# 使用随机Id
POST /<index>/_doc
{
"key":"value"
}
PUT /<index>/_doc/<Id>
{
"key":"value"
}
# 可传参数q
# 根据字段值查询 ?q=<条件>:<值>
# 查询范围 field[MIN TO MAX]
# 分页 from size
# 排序 sort sort=: desc
# 仅输出某些字段 _source=field,field
GET /<index>/_search
GET //_doc/
# PUT和POST请求都可以执行,全部字段均会被修改更新,可以新增字段,当ID未匹配到则执行新增
# 若Id存在,会将文档修改为以下内容
POST /<index>/_doc/<Id>
{
"key":"value"
}
# 仅支持POST请求,只修改部分字段数据, 字段不存在则在则创建
# 当ID未匹配上时,报错
POST /<index>/_update/<Id>/
{
"doc": {
"key":"value"
}
}
ES使用版本version来管理文档,在更新的时候可以加上版本来控制并发
参数说明:
# 根据查询结果返回的seq_no和primary_term参数更新
POST /<index>/_doc/<Id>?if_seq_no=11&if_primary_term=1
{
"doc":{
"field": "value"
}
}
DELETE //_doc/
# 多Id查询
# 单索引查询
POST /<index>/_mget
{
"ids": [
"" ,
"" ,
""
]
}
# 多索引查询
{
"docs": [
{
"_index": "" ,
"_id": ""
},
{
"_index": "" ,
"_id": ""
}
]
}
# 若索引存在则更新、反之就新增
POST _bulk
{ "create" : { "_index" : "" , "_id": "" } }
{"key": "value"}
{ "create" : { "_index" : "" , "_id": "" } }
{"key": "value"}
# 命令下一行需要紧跟着data数据
POST _bulk
{"update": {"_index": "" ,"_id": "" }}
{"doc": {"key": "value"}}
{"update": {"_index": "" ,"_id": "" }}
{"doc": {"key": "value"}}
POST _bulk
{ "delete" : {"_index": "" ,"_id": "" }}
{ "delete" : {"_index": "" ,"_id": "" }}
# 使用_bulk命令可以进行文档的批量增删改
POST _bulk
{ "create" : {"_index" : "" , "_id": "" }}
{"key": "value"}
{ "update" : {"_index" : "" , "_id": "" }}
{ "doc" : {"key": "value"}}
{ "delete" : {"_index" : "my_index3", "_id": "" }}
当我们开始在 Elasticsearch 插入数据,你就可以通过_search 方式发送请求来进行搜索,如果使用匹配搜索功能,在请求体中使用 Elasticsearch Query DSL 指定搜索条件。你也可以在请求头指定要搜索的索引名称。
关键字 | 查询范围 | 备注 |
---|---|---|
match_all | 查询所有 | |
match | 匹配查询 | |
bool | 联合查询 | |
term | 词条精准查询 | |
range | 范围查询 |
参数 | 意义 | 备注 |
---|---|---|
must | 必须同时满足 | AND |
must_not | 必须同时不满足 | NOT |
should | 满足其中一个条件 | OR |
filter | 过滤条件必须匹配 |
参数 | 意义 | 备注 |
---|---|---|
took | 整个搜索花费的毫秒数 | |
timed_out | 查询是否超时 | |
_shards | 参与查询的分片数 成功/失败 | |
hits | 查询匹配的根节点 | |
hits[] | hits数组包含了匹配到的前10条数据 | |
hits.total.value | 表示匹配到的文档总数 | |
hits._index | 索引 | |
hits_type | 文档类型 | |
hits._id | 文档标识符 | |
hits._source | 文档存储的实际数据 | |
hits._score | 相关性得分 |
GET /<index>/_search
{
"query": {
"match_all": {}
}
}
GET /<index>/_search
{
"query": {
"match": {
"name": "ichpan"
}
}
}
GET /<index>/_search
{
"query": {
"match_all": {}
},
"_source": [
"field1",
"field2"
]
}
多个条件之间使用空格分割
GET /test/_search
{
"query": {
"match": {
"name": "ichpan yjiahao"
}
}
}
排序后score返回的值为null,order支持 desc/asc
GET /test/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"age": {
"order": "desc"
}
}
]
}
GET _analyze
{
"analyzer": "standard",
"text": "楼下安同学"
}
GET /<index>/_search
{
"query": {
"ids": {
"values":[Id1, Id2, Id3]
}
}
}
GET //_mget
{
"ids": [
Id1,
Id2,
Id3
]
}
# 同时查询与两个索引下的数据
GET /_mget
{
"docs": [
{
"_index": "index1",
"_id": "1"
},
{
"_index": "index2",
"_id": "2"
}
]
}
GET /_msearch
{"index":"index1"}
{"query":{"match_all":{}}}
{"index":"index2"}
{"query":{"match_all":{}}}
像match或 query_string 这样的查询是高层查询,它们了解字段映射的信息:如果查询日期或整数字段,它们会将查询字符串分别作为日期或整数对待。如果查询一个未分析的精确值字符串字段,它们会将整个查询字符串作为单个词项对待。但如果要查询一个已分析的全文字段,它们会先将查询字符串传递到一个合适的分析器,然后生成一个供查询的词项列表。一旦组成了词项列表,这个查询会对每个词项逐一执行底层的查询,再将结果合并,然后为每个文档生成一个最终的相关度评分。
匹配查询match是个核心查询。无论需要查询什么字段, match 查询都应该会是首选的查询方式。它是一个高级全文查询 ,这表示它既能处理全文字段,又能处理精确字段。
# 单个词
GET /<index>/_search
{
"query": {
"match": {
"profession": "楼下安同学"
}
}
}
# 多个词用逗号隔开
GET /student_info/_search
{
"query": {
"match": {
"profession": "你好, 楼下安同学"
}
}
}
match查询还可以接受operator 操作符作为输入参数,默认情况下该操作符是or。我们可以将它修改成 and
让所有指定词项都必须匹配
# 查询索引test中name为ichpan和yjiahao的文档
GET /test/_search
{
"query": {
"match": {
"name": {
"query": "ichpan yjiahao",
"operator": "and"
}
}
}
}
我们既想查询包含那些可能相关的文档,同时又排除那些不太相关的文档。
match查询支持minimum_should_match最小匹配参数,这让我们可以指定必须匹配的词项数用来表示一个文档是否相关。我们可以将其设置为某个具体数字,也可设置为一个百分数。
GET /test/_search
{
"query": {
"match": {
"name": {
"query": "ichpan yjiahao",
"minimum_should_match": "30%"
}
}
}
}
指定字段中出现的值
# 匹配字段name和desc字段中包含拆出来的词语的结果
GET /<index>/_search
{
"query": {
"multi_match": {
"query": "楼下安同学",
"fields": ["name", "desc" ]
}
}
}
match_phrase短语搜索,要求所有的分词必须同时出现在文档中,同时位置必须紧邻一致
GET /<index>/_search
{
"query": {
"match_phrase": {
"name": "楼下安同学"
}
}
}
返回带有html标签的检索结果
GET /test/_search
{
"query": {
"match": {
"name": "ichpan"
}
},
"highlight": {
"fields": {
"name": {}
}
}
}
GET /<index>/_search
{
"query": {
"match_phrase_prefix": {
"name": "ich"
}
}
}
布尔值查询bool,筛选必须符合条件的数据 布尔条件可选条件见 2.1条件语句
# 布尔条件可选条件见 2.1条件语句
GET /test/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "ichpan"
}
}
]
}
},
"from": 0,
"size": 10
}
过滤只会筛选出符合的文档,并不计算得分,且它可以缓存文档。所以,从性能考虑,过滤比查询更快。过滤适合在大范围筛选数据,而查询则适合精确匹配数据。一般应用时,应先使用过滤操作过滤数据,然后使用查询匹配数据。
GET /test/_search
{
"query": {
"bool": {
"must": [
{
"match_all": {}
}
],
"filter": {
"range": {
"age": {
"gte": 10,
"lte": 30
}
}
}
}
}
}
GET /<index>/_search
{
"query": {
"fuzzy": {
"name": "安"
}
}
}
term 或fuzzy 这样的底层查询不需要分析阶段,它们对单个词项进行操作。用term查询词项Foo只要在倒排索引中查找准确词项 ,并且用 TF/IDF 算法为每个包含该词项的文档计算相关度评分 _score。
# 关键词查询
GET /<index>/_search
{
"query": {
"term": {
"name.keyword": "foo"
}
}
}
# 多条件查询
GET /<index>/_search
{
"query": {
"terms": {
"age": [19,20,21,22]
}
}
}
大于-gt,小于-lt,大于等于-gte,小于等于-lte
GET /<inex>/_search
{
"query": {
"range": {
"age":{
"gte": 19,
"lte": 21
}
}
}
}
GET //_search
{
"query": {
"range": {
"birthday":{
"gte": "2001-06-15",
"lte": "2001-09-20"
}
}
}
}
GET /<index>/_search
{
"query": {
"range": {
"age":{
"from": 19,
"to": 21
}
}
}
}
GET /<index>/_search
{
"query": {
"range": {
"age": {
"from": 19,
"to": 21,
"include_lower": false,
"include_upper": false
}
}
}
}
? 匹配任意数量字符,*用来匹配零个或者多个字符,主要用于英文检索
# *匹配
GET /student_info/_search
{
"query": {
"wildcard": {
"name": "小*"
}
}
}
# ?匹配
GET /student_info/_search
{
"query": {
"wildcard": {
"name": "ich?n"
}
}
}
约束条件参考 DSL条件-约束条件
2.8 分页查询
对于非深度分页,简单查询时,一般使用from和size进行分页查询
from: 分页起始位置
size: 每页数据大小
GET /<index>/_search
{
"query": {
"match_all": {}
},
"from": 1,
"size": 2
}
ES对于from和size的个数是有限制的,默认限制二者之和不能超过1w,超过后会报错max_result_window参数作为保护措施,虽然这个参数可以修改,也可以在配置文件配置。但是最好不要这么做,当所请求的数据总量大于1w时,应使用ES游标(scroll查询)来代替from+size。如果需要深度分页对服务器压力会变大。如果确认需要设置,则需要提前预估启动内存大小。
scoll 游标查询,指定 scroll=时间 ,指定保存的分钟数,第一次发起请求放回的是数据+_scroll_id ,后面通过 _scroll_id 去请求数据,适合大批量查询。游标查询,其实是在 es 里面缓存了结果 ,然后一次一次的去取,所以发起第一次请求的时候只有size ,没有from,后面的请求只有 scroll_id 和 scroll 时间
# 年龄大于18,每页2条,保存1分钟
GET /<index>/_search?scroll=1m
{
"query": {
"range": {
"age":{
"gt": 18
}
}
},
"size": 2
}
from + size的分页方式虽然是最灵活的分页方式,但当分页深度达到一定程度将会产生深度分页的问题。scroll能够解决深度分页的问题,但是其无法实现实时查询,即当scroll_id生成后无法查询到之后数据的变更,因为其底层原理是生成数据的快照。ES-5.X之后 search_after应运而生,使用search_after必须添加排序"sort"条件
# 指定了根据ID升序,年龄倒序,2个排序条件,search_after中[起始ID,起始年龄]
GET /student_info/_search
{
"query": {
"match_all": {}
},
"search_after": [
11000,20
],
"size": 2,
"sort": [
{"_id": "asc"},
{"age": "desc"}
]
}
聚合查询是开发中常见的场景,一般包含。求和、最大值、最小值、平均值、总记录数等。text类型是不支持聚合的,size: 0 参数表示不用返回文档列表,只返回汇总的数据即可
"aggregations" : {
"" : { <!--聚合的名字 -->
"" : { <!--聚合的类型 -->
<aggregation_body> <!--聚合体:对哪些字段进行聚合 -->
}
[,"meta" : { [<meta_data_body>] } ]? <!--元 -->
[,"aggregations" : { [<sub_aggregation>]+ } ]? <!--在聚合里面在定义子聚合 -->
}
}
GET /<inedx>/_search
{
"size": 0,
"aggs": {
"sum_age": {
"sum": {
"field":"age"
}
}
}
}
GET /<index>/_search
{
"size": 0,
"aggs": {
"max_age": {
"max": {
"field":"age"
}
}
}
}
GET /<index>/_search
{
"size": 0,
"aggs": {
"min_age": {
"min": {
"field":"age"
}
}
}
}
GET /<index>/_search
{
"size": 0,
"aggs": {
"avg_age": {
"avg": {
"field":"age"
}
}
}
}
# 类似mysql的 count distinct
GET /<index>/_search
{
"size": 0,
"aggs": {
"age_count": {
"cardinality": {
"field": "age.keyword"
}
}
}
}
GET /<index>/_search
{
"size": 0,
"aggs": {
"max_age": {
"max": {
"field": "age"
}
},
"min_age": {
"min": {
"field": "age"
}
},
"avg_age": {
"avg": {
"field": "age"
}
}
}
}
stats 统计,请求后会直接显示多种聚合结果,总记录数,最大值,最小值,平均值,汇总值
GET /<index>/_search
{
"size": 0,
"aggs": {
"age_stats": {
"stats": {
"field":"age"
}
}
}
}
对指定字段的值按从小到大累计每个值对应的文档数的占比,返回指定占比比例对应的值
GET /<index>/_search
{
"size": 0,
"aggs": {
"age_percentiles": {
"percentiles": {
"field": "age"
}
}
}
}
这里指定值,查占比。注意占比是小于文档值的比例
GET /<index>/_search
{
"size": 0,
"aggs": {
"age_percentiles": {
"percentile_ranks": {
"field": "age",
"values": [
22,
25,
33
]
}
}
}
}
{
"size": 0,
"aggs": {
"load_time_outlier": {
"percentiles": {
"field": "salary",
"percents": [
50,
99
],
"keyed": false
}
}
}
}
案例1:根据性别分组。展示工资排名top3
GET /<index>/_search?size=0
{
"aggs": {
"top_tags": {
"terms": {
"field": "sex"
},
"aggs": {
"top_sales_hits": {
"top_hits": {
"sort": [
{
"salary": {
"order": "desc"
}
}
],
"_source": {
"includes": [
"name",
"sex",
"salary"
]
},
"size": 3
}
}
}
}
}
}
# 根据性别分组求平均工资
GET /<index>/_search
{
"size":0,
"aggs": {
"top_tags": {
"terms": {
"field": "sex"
},
"aggs": {
"avg_salary": {
"avg": {
"field": "salary"
}
}
}
}
}
}
# 统计年龄 >=25 的记录数
GET /<index>/_count
{
"query": {
"range": {
"age":{
"gte": 25
}
}
}
}
# 统计年龄 >=25 的记录数
GET /<index>/_search?size=0
{
"query": {
"range": {
"age":{
"gte": 25
}
}
}
}
此文档对ElasticSearch基础操作进行了全面总结,在各种语言中操作ElasticSearch主要写DSL语句,掌握底层原理有助于我们快速研发。文档持续更新补充中…