ElasticSearch笔记02-ElasticSearch入门

news2024/11/16 17:31:49

ElasticSearch安装

下载软件

ElasticSearch的官网,视频教程里用的Version是7.8.0,所以,我们也是用7.8.0版本的ElasticSearch。
下载地址:https://www.elastic.co/cn/downloads/past-releases#elasticsearch,然后搜索7.8.0版本即可。
按照视频里讲的,下载了Windows版本的ElasticSearch,当然,生产环境肯定是Linux版本的。

安装软件

Windows版本的安装很简单,解压后就可以使用了。

目录含义
bin可执行脚本目录
config配置目录
jdk内置JDK目录
lib类库
logs日志目录
modules模块目录
plugins插件目录

解压缩后,进入到bin目录下,运行elasticsearch.bat文件就启动了ElasticSearch服务。这里需要留意两个端口:9200和9300。
9200端口为浏览器访问的http协议RESTful端口,9300端口为Elasticsearch集群间组件的通信端口。
此时打开浏览器访问:http://localhost:9200/,可以看到内容,表示ElasticSearch服务启动成功。

问题解决

ElasticSearch是基于Java开发的,7.8.0版本的ElasticSearch需要JDK1.8及以上版本,默认的安装包里带有JDK,如果系统配置了JAVA_HOME,会使用系统配置的JDK,如果没有配置,会使用安装包里自带的JDK,建议使用系统配置的JDK。
如果出现启动后闪退的情况,可能是空间不足,需要修改config/jvm.options配置文件。

# 设置JVM初始内存为1G。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存
# Xms represents the initial size of total heap space
# 设置JVM最大可用内存为1G
# Xmx represents the maximum size of total heap space
-Xms1g
-Xmx1g

ElasticSearch基本操作

RESTful

REST指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是RESTful。Web应用程序最重要的REST原则是,客户端和服务器之间的交互在请求之间是无状态的。从客户端到服务器的每个请求都必须包含理解请求所必需的信息。如果服务器在请求之间的任何时间点重启,客户端不会得到通知。此外,无状态请求可以由任何可用服务器回答,这十分适合云计算之类的环境。客户端可以缓存数据以改进性能。
在服务器端,应用程序状态和功能可以分为各种资源。资源是一个有趣的概念实体,它向客户端公开。资源的例子有:应用程序对象、数据库记录、算法等等。每个资源都使用URI(Universal Resource Identifier)得到一个唯一的地址。所有资源都共享统一的接口,以便在客户端和服务器之间传输状态。使用的是标准的HTTP方法,比如GET、PUT、POST和DELETE。
在REST样式的Web服务中,每个资源都有一个地址。资源本身都是方法调用的目标,方法列表对所有资源都是一样的。这些方法都是标准方法,包括HTTP GET、POST、PUT、DELETE,还可能包括HEAD和OPTIONS。简单的理解就是,如果想要访问互联网上的资源,就必须向资源所在的服务器发出请求,请求体中必须包含资源的网络路径,以及对资源进行的操作(增删改查)。

客户端安装

如果直接通过浏览器向Elasticsearch服务器发请求,那么需要在发送的请求中包含HTTP标准的方法,而HTTP的大部分特性且仅支持GET和POST方法。所以为了能方便地进行客户端的访问,可以使用Postman软件Postman是一款强大的网页调试工具,提供功能强大的Web API和HTTP请求调试。
软件功能强大,界面简洁明晰、操作方便快捷,设计得很人性化。Postman中文版能够发送任何类型的HTTP请求(GET, HEAD, POST, PUT……),不仅能够表单提交,且可以附带任意类型请求体。
Postman官网
Postman下载

数据格式

Elasticsearch是面向文档型数据库,一条数据在这里就是一个文档。为了方便大家理解,我们将Elasticsearch里存储文档数据和关系型数据库MySQL存储数据的概念进行一个类比。
在这里插入图片描述

ES里的Index可以看做一个库,而Types相当于表,Documents则相当于表的行。
这里Types的概念已经被逐渐弱化,Elasticsearch 6.X中,一个index下已经只能包含一个type,Elasticsearch 7.X中,Type的概念已经被删除了。
用JSON作为文档序列化的格式。

HTTP操作

索引操作

创建索引

# 创建一个名为my_index的索引
PUT /my_index
# 结果
{
  "acknowledged": true,
  "shards_acknowledged": true,
  "index": "my_index"
}
# 再次执行这个请求,会返回错误信息
{
  "error": {
    "root_cause": [
      {
        "type": "resource_already_exists_exception",
        "reason": "index [my_index/_vtClcNVRtGutbWMgIhpAg] already exists",
        "index_uuid": "_vtClcNVRtGutbWMgIhpAg",
        "index": "my_index"
      }
    ],
    "type": "resource_already_exists_exception",
    "reason": "index [my_index/_vtClcNVRtGutbWMgIhpAg] already exists",
    "index_uuid": "_vtClcNVRtGutbWMgIhpAg",
    "index": "my_index"
  },
  "status": 400
}

查看所有索引

# 查看所有索引
GET /_cat/indices
# 结果
yellow open my_index _vtClcNVRtGutbWMgIhpAg 1 1 0 0 208b 208b
表头含义
health当前服务器健康状态:green-集群完整,yellow-单点正常、集群不完整,red-单点不正常
status索引打开、关闭状态
index索引名
uuid索引唯一编号
pri主分片数量
rep副本数量
docs.count可用文档数量
docs.deleted文档删除状态(逻辑删除)
store.size主分片和副分片整体占空间大小
pri.store.size主分片占空间大小

查看单个索引

# 查看单个索引
GET /my_index
# 结果
{
  "my_index": {
    "aliases": {},
    "mappings": {},
    "settings": {
      "index": {
        "creation_date": "1685762192047",
        "number_of_shards": "1",
        "number_of_replicas": "1",
        "uuid": "_vtClcNVRtGutbWMgIhpAg",
        "version": {
          "created": "7080099"
        },
        "provided_name": "my_index"
      }
    }
  }
}

删除索引

# 删除索引
DELETE /my_index
# 结果
{
  "acknowledged": true
}
# 再次执行这个请求,会返回错误信息
{
  "error": {
    "root_cause": [
      {
        "type": "index_not_found_exception",
        "reason": "no such index [my_index]",
        "resource.type": "index_or_alias",
        "resource.id": "my_index",
        "index_uuid": "_na_",
        "index": "my_index"
      }
    ],
    "type": "index_not_found_exception",
    "reason": "no such index [my_index]",
    "resource.type": "index_or_alias",
    "resource.id": "my_index",
    "index_uuid": "_na_",
    "index": "my_index"
  },
  "status": 404
}

文档操作

创建文档

接下来,我们创建文档,一个文档相当于关系型数据库表中的一行数据。

# 创建文档
POST /my_index/_doc
{
  "name": "王劭阳",
  "sex": "男",
  "address": "山东省济南市"
}
# 结果
{
  "_index": "my_index",
  "_type": "_doc",
  "_id": "G4JNf4gB5UHhrLgfdkiL",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 0,
  "_primary_term": 1
}

在早期ElasticSearch里,有type的概念,在ElasticSearch 7版本,移除了type的概念,历史版本创建的数据,默认置为_doc。在ElasticSearch 8版本,完全废弃了type的概念。
在创建的时候,由于没有指定数据唯一标识,ElasticSearch会随机生成一个,如果想要指定唯一标识,可以在创建的路径上加上标识。

# 创建指定id的文档
POST /my_index/_doc/1
{
  "name": "王劭阳1",
  "sex": "男",
  "address": "山东省济南市"
}
# 结果
{
  "_index": "my_index",
  "_type": "_doc",
  "_id": "1",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 1,
  "_primary_term": 1
}

查看文档

# 根据id查看文档
GET /my_index/_doc/1
# 结果
{
  "_index": "my_index",
  "_type": "_doc",
  "_id": "1",
  "_version": 1,
  "_seq_no": 1,
  "_primary_term": 1,
  "found": true,
  "_source": {
    "name": "王劭阳1",
    "sex": "男",
    "address": "山东省济南市"
  }
}

修改文档

# 根据id修改文档
POST /my_index/_doc/1
{
  "name": "王劭阳update",
  "sex": "男",
  "address": "山东省济南市update"
}
# 结果
{
  "_index": "my_index",
  "_type": "_doc",
  "_id": "1",
  "_version": 2,
  "result": "updated",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 2,
  "_primary_term": 1
}

这个操作是一个全字段替换,直接将请求体的内容完全替换到文档里。

修改字段

# 根据id修改字段
POST /my_index/_update/1
{
  "doc": {
    "name": "王劭阳update1"
  }
}
# 结果
{
  "_index": "my_index",
  "_type": "_doc",
  "_id": "1",
  "_version": 3,
  "result": "noop",
  "_shards": {
    "total": 0,
    "successful": 0,
    "failed": 0
  },
  "_seq_no": 3,
  "_primary_term": 1
}

删除文档

# 根据id删除文档
DELETE /my_index/_doc/1
# 结果
{
  "_index": "my_index",
  "_type": "_doc",
  "_id": "1",
  "_version": 6,
  "result": "deleted",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 6,
  "_primary_term": 1
}
# 再次执行这个请求,会返回错误信息
{
  "_index": "my_index",
  "_type": "_doc",
  "_id": "1",
  "_version": 7,
  "result": "not_found",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 7,
  "_primary_term": 1
}

条件删除文档

# 条件删除文档
POST /my_index/_delete_by_query
{
  "query": {
    "match": {
      "name": "王劭阳"
    }
  }
}
# 结果
{
  "took": 2276,
  "timed_out": false,
  "total": 1,
  "deleted": 1,
  "batches": 1,
  "version_conflicts": 0,
  "noops": 0,
  "retries": {
    "bulk": 0,
    "search": 0
  },
  "throttled_millis": 0,
  "requests_per_second": -1.0,
  "throttled_until_millis": 0,
  "failures": []
}

映射操作

有了索引库,等于有了数据库中的database。接下来就需要建索引库(index)中的映射了,类似于数据库(database)中的表结构(table)。
创建数据库表需要设置字段名称,类型,长度,约束等;索引库也一样,需要知道这个类型下有哪些字段,每个字段有哪些约束信息,这就叫做映射(mapping)。

创建映射

# 创建映射
PUT /my_index/_mapping
{
  "properties": {
    "name": {
      "type": "text",
      "index": true
    },
    "sex": {
      "type": "text",
      "index": false
    },
    "age": {
      "type": "long",
      "index": false
    }
  }
}
# 结果
{
  "acknowledged": true
}

在创建的时候,报错了,提示我某个字段已经有了mapping,这是因为我们先插入了文档,没有创建映射,ES自动帮我们创建的映射和我们想要创建的映射冲突导致的,我的解决方法是:把index_name删掉重建,但是不插入文档,然后执行创建映射的操作。
在properties里,有多个对象,查看每一个对象的构成。
字段名:任意写,下面指定多个属性
type:类型,ES中支持多种数据类型:

  • String类型的text:可分词
  • String类型的keyword:不可分次
  • Numerical类型的基本数据类型:long、integer、short、byte、double、float、half_float
  • Numerical类型的浮点数高精度类型:scaled_float
  • Date:日期类型
  • Array:数组类型
  • Object:对象类型

index:是否索引,默认为true

  • true:字段会被索引,可以用来搜索
  • false:字段不会被索引,不能用来搜索

store:是否将数据进行独立存储,默认为false。原始的文本会存储在_source里面,默认情况下其他提取出来的字段都不是独立存储的,是从_source里面提取出来的。当然你也可以独立的存储某个字段,只要设置"store": true 即可,获取独立存储的字段要比从_source中解析快得多,但是也会占用更多的空间,所以要根据实际业务需求来设置
analyzer:分词器

查看映射

# 查看映射
GET /my_index/_mapping
# 结果
{
  "my_index1": {
    "mappings": {
      "properties": {
        "age": {
          "type": "long",
          "index": false
        },
        "name": {
          "type": "text"
        },
        "address": {
          "type": "text",
          "index": true
        }
      }
    }
  }
}

索引映射关联

索引和映射要建立关联,才能方便后面的查询,上一步已经有映射关联了,所以这里再给index_name创建映射会报错,为了演示效果,先把索引删除,再创建索引映射关联。

# 索引映射关联
PUT /my_index
{
  "settings": {},
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "index": true
      },
      "sex": {
        "type": "text",
        "index": false
      },
      "address": {
        "type": "text",
        "index": true
      }
    }
  }
}
# 结果
{
  "acknowledged": true,
  "shards_acknowledged": true,
  "index": "my_index"
}

高级查询

为了演示查询的功能,我们重建索引和映射,并插入4个文档信息用于查询。

# 创建索引和映射
PUT /my_index
{
  "settings": {},
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "index": true
      },
      "sex": {
        "type": "text",
        "index": false
      },
      "address": {
        "type": "text",
        "index": true
      }
    }
  }
}
# 插入数据
POST /my_index/_doc/1
{
  "name": "张三",
  "sex": "男",
  "address": "山东省济南市"
}
POST /my_index/_doc/2
{
  "name": "李四",
  "sex": "女",
  "address": "山东省淄博市"
}
POST /my_index/_doc/3
{
  "name": "王五",
  "sex": "男",
  "address": "山东省聊城市"
}
POST /my_index/_doc/4
{
  "name": "赵六",
  "sex": "女",
  "address": "山东省青岛市"
}
查询所有文档
# 查询所有文档
GET /_search
{
  "from": 0,
  "size": 10,
  "query": {
    "match_all": {}
  }
}
# 结果
{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 4,
      "relation": "eq"
    },
    "max_score": 1.0,
    "hits": [
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.0,
        "_source": {
          "name": "张三",
          "sex": "男",
          "address": "山东省济南市"
        }
      },
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "2",
        "_score": 1.0,
        "_source": {
          "name": "李四",
          "sex": "女",
          "address": "山东省淄博市"
        }
      },
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "3",
        "_score": 1.0,
        "_source": {
          "name": "王五",
          "sex": "男",
          "address": "山东省聊城市"
        }
      },
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "4",
        "_score": 1.0,
        "_source": {
          "name": "赵六",
          "sex": "女",
          "address": "山东省青岛市"
        }
      }
    ]
  }
}
匹配查询
# 匹配查询
GET /_search
{
  "query": {
    "match": {
      "name": "张三"
    }
  }
}
# 结果
{
  "took": 13,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 2.4079456,
    "hits": [
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "1",
        "_score": 2.4079456,
        "_source": {
          "name": "张三",
          "sex": "男",
          "address": "山东省济南市"
        }
      }
    ]
  }
}
字段匹配查询
# 字段匹配查询
GET /_search
{
  "query": {
    "multi_match": {
      "query": "李四",
      "fields": [
        "name",
        "address"
      ]
    }
  }
}
# 结果
{
  "took": 6,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 2.4079456,
    "hits": [
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "2",
        "_score": 2.4079456,
        "_source": {
          "name": "李四",
          "sex": "女",
          "address": "山东省淄博市"
        }
      }
    ]
  }
}
关键字精确查询

不对查询条件进行分词,这里没有查到好像和分词有关系,先学习语法吧,这里我也不大清楚为什么查不到。

# 关键字精确查询
GET /_search
{
  "query": {
    "term": {
      "address": {
        "value": "山东省青岛市"
      }
    }
  }
}
# 结果
{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 0,
      "relation": "eq"
    },
    "max_score": null,
    "hits": []
  }
}
多关键字精确查询
# 多关键字精确查询
GET /_search
{
  "query": {
    "terms": {
      "address": [
        "山东省青岛市",
        "山东省淄博市"
      ]
    }
  }
}
# 结果
{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 0,
      "relation": "eq"
    },
    "max_score": null,
    "hits": []
  }
}
指定查询字段

只想查询name和address,通过_source可以指定。

# 指定查询字段
GET /my_index/_search
{
  "_source": [
    "name",
    "address"
  ],
  "query": {
    "match": {
      "name": "王五"
    }
  }
}
# 结果
{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 2.4079456,
    "hits": [
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "3",
        "_score": 2.4079456,
        "_source": {
          "address": "山东省聊城市",
          "name": "王五"
        }
      }
    ]
  }
}
过滤字段

通过includes和excludes作用于_source,指定想要显示的字段和不想显示的字段。

# 指定查询字段
GET /my_index/_search
{
  "_source": {
    "includes": [
      "name",
      "address"
    ]
  },
  "query": {
    "match": {
      "name": "赵六"
    }
  }
}
# 结果
{
  "took": 5,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 2.4079456,
    "hits": [
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "4",
        "_score": 2.4079456,
        "_source": {
          "address": "山东省青岛市",
          "name": "赵六"
        }
      }
    ]
  }
}
组合查询

通过mustmust_notshould方式进行组合,构造出查询条件。

# 组合查询
GET /my_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "sex": "男"
          }
        }
      ],
      "must_not": [
        {
          "match": {
            "address": "山东省济南市"
          }
        }
      ],
      "should": [
        {
          "match": {
            "name": "王五"
          }
        }
      ]
    }
  }
}
# 结果
{
  "took": 7,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 0,
      "relation": "eq"
    },
    "max_score": null,
    "hits": []
  }
}
范围查询
# 范围查询
GET /my_index/_search
{
  "query": {
    "range": {
      "age": {
        "gt": "大于",
        "gte": "大于等于",
        "lt": "小于",
        "lte": "小于等于"
      }
    }
  }
}
# 结果
{
  "took": 4,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 0,
      "relation": "eq"
    },
    "max_score": null,
    "hits": []
  }
}
模糊查询

返回包含与搜索字词相似字词的文档。
编辑距离是将一个术语转换为另一个术语所需的一个字符更改的次数,这些更改包括:更改字符、删除字符、插入字符、转置两个相邻字符。
为了找到相似的术语,模糊查询会在指定编辑距离内创建一组搜索词的所有可能变体或扩展,然后查询返回每个扩展的完全匹配。
通过fuzziness修改编辑距离,一般使用AUTO,根据术语的长度生成编辑距离。

# 模糊查询
GET /my_index/_search
{
  "query": {
    "fuzzy": {
      "address": {
        "value": "山东省聊城市",
        "fuzziness": "2"
      }
    }
  }
}
# 结果
{
  "took": 12,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 0,
      "relation": "eq"
    },
    "max_score": null,
    "hits": []
  }
}
单字段排序

这里必须带上keyword,否则直接报错,不知道为什么,而且排序后的结果也很奇怪,跟我想象的也不一样。感觉还是和分词有关系,上面的几个查询,如果带上keyword,就可以查到东西,应该也是类似的原因。

# 单字段排序
GET /my_index/_search
{
  "query": {
    "match_all": {
    }
  },
  "sort": [
    {
      "name.keyword": {
        "order": "asc"
      }
    }
  ]
}
# 结果
{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 4,
      "relation": "eq"
    },
    "max_score": null,
    "hits": [
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "1",
        "_score": null,
        "_source": {
          "name": "张三",
          "sex": "男",
          "address": "山东省济南市"
        },
        "sort": [
          "张三"
        ]
      },
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "2",
        "_score": null,
        "_source": {
          "name": "李四",
          "sex": "女",
          "address": "山东省淄博市"
        },
        "sort": [
          "李四"
        ]
      },
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "3",
        "_score": null,
        "_source": {
          "name": "王五",
          "sex": "男",
          "address": "山东省聊城市"
        },
        "sort": [
          "王五"
        ]
      },
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "4",
        "_score": null,
        "_source": {
          "name": "赵六",
          "sex": "女",
          "address": "山东省青岛市"
        },
        "sort": [
          "赵六"
        ]
      }
    ]
  }
}
多字段排序
# 多字段排序
GET /my_index/_search
{
  "query": {
    "match_all": {
    }
  },
  "sort": [
    {
      "name.keyword": {
        "order": "asc"
      }
    },
    {
      "address.keyword": {
        "order": "desc"
      }
    }
  ]
}
# 结果
{
  "took": 2049,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 4,
      "relation": "eq"
    },
    "max_score": null,
    "hits": [
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "4",
        "_score": null,
        "_source": {
          "name": "赵六",
          "sex": "女",
          "address": "山东省青岛市"
        },
        "sort": [
          "赵六",
          "山东省青岛市"
        ]
      },
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "3",
        "_score": null,
        "_source": {
          "name": "王五",
          "sex": "男",
          "address": "山东省聊城市"
        },
        "sort": [
          "王五",
          "山东省聊城市"
        ]
      },
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "2",
        "_score": null,
        "_source": {
          "name": "李四",
          "sex": "女",
          "address": "山东省淄博市"
        },
        "sort": [
          "李四",
          "山东省淄博市"
        ]
      },
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "1",
        "_score": null,
        "_source": {
          "name": "张三",
          "sex": "男",
          "address": "山东省济南市"
        },
        "sort": [
          "张三",
          "山东省济南市"
        ]
      }
    ]
  }
}
高亮查询

Elasticsearch可以对查询内容中的关键字部分,进行标签和样式(高亮)的设置。在使用match查询的同时,加上一个highlight属性:
pre_tags:前置标签
post_tags:后置标签
fields:需要高亮的字段
title:声明title字段需要高亮,后面可以为这个字段设置特有配置,也可以为空

# 高亮查询
GET /my_index/_search
{
  "query": {
    "match": {
      "name": {
        "query": "张三"
      }
    }
  },
  "highlight": {
    "pre_tags": "<font color='red'>",
    "post_tags": "</font>",
    "fields": {
      "name": {}
    }
  }
}
# 结果
{
  "took": 3,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 2.4079456,
    "hits": [
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "1",
        "_score": 2.4079456,
        "_source": {
          "name": "张三",
          "sex": "男",
          "address": "山东省济南市"
        },
        "highlight": {
          "name": [
            "<font color='red'>张</font><font color='red'>三</font>"
          ]
        }
      }
    ]
  }
}
分页查询

通过设置from和size的值来控制分页,from默认从0开始,from = (pageNum - 1) * size

# 分页查询
GET /my_index/_search
{
  "query": {
    "match_all": {
    }
  },
  "from": 0,
  "size": 2
}
# 结果
{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 4,
      "relation": "eq"
    },
    "max_score": 1.0,
    "hits": [
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.0,
        "_source": {
          "name": "张三",
          "sex": "男",
          "address": "山东省济南市"
        }
      },
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "2",
        "_score": 1.0,
        "_source": {
          "name": "李四",
          "sex": "女",
          "address": "山东省淄博市"
        }
      }
    ]
  }
}
聚合查询

聚合查询用于对文档进行统计分析,类似于group by,因为没有合适的文档用于展示,所以下面查询都是空的。

# 聚合查询之最大值
GET /my_index/_search
{
  "aggs": {
    "max_address": {
      "max": {
        "field": "address"
      }
    }
  },
  "size": 0
}

# 聚合查询之最小值
GET /my_index/_search
{
  "aggs": {
    "min_address": {
      "min": {
        "field": "address"
      }
    }
  },
  "size": 0
}

# 聚合查询之求和
GET /my_index/_search
{
  "aggs": {
    "sum_address": {
      "sum": {
        "field": "address"
      }
    }
  },
  "size": 0
}

# 聚合查询之求平均
GET /my_index/_search
{
  "aggs": {
    "avg_address": {
      "avg": {
        "field": "address"
      }
    }
  },
  "size": 0
}

# 聚合查询值求去重后获取总数
GET /my_index/_search
{
  "aggs": {
    "distinct_address": {
      "cardinality": {
        "field": "address"
      }
    }
  },
  "size": 0
}

# 聚合操作之state聚合,对某一个字段一次性返回count、max、min、avg、sum五个指标
GET /my_index/_search
{
  "aggs": {
    "state_address": {
      "stats": {
        "field": "address"
      }
    }
  },
  "size": 0
}
桶聚合查询

桶聚合相当于sql中的group by语句。

GET /my_index/_search
{
  "aggs": {
    "sex_group_by": {
      "terms": {
        "field": "sex.keyword"
      }
    }
  }
}
# 结果
{
  "took": 7,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 4,
      "relation": "eq"
    },
    "max_score": 1.0,
    "hits": [
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.0,
        "_source": {
          "name": "张三",
          "sex": "男",
          "address": "山东省济南市"
        }
      },
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "2",
        "_score": 1.0,
        "_source": {
          "name": "李四",
          "sex": "女",
          "address": "山东省淄博市"
        }
      },
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "3",
        "_score": 1.0,
        "_source": {
          "name": "王五",
          "sex": "男",
          "address": "山东省聊城市"
        }
      },
      {
        "_index": "my_index",
        "_type": "_doc",
        "_id": "4",
        "_score": 1.0,
        "_source": {
          "name": "赵六",
          "sex": "女",
          "address": "山东省青岛市"
        }
      }
    ]
  },
  "aggregations": {
    "sex_group_by": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "女",
          "doc_count": 2
        },
        {
          "key": "男",
          "doc_count": 2
        }
      ]
    }
  }
}

Java API操作

ElasticSearch是由Java语言开发的,所以可以通过Java API的方式访问ElasticSearch。

创建Maven项目

在pom.xml里添加依赖。

<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>7.8.0</version>
</dependency>
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.8.0</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.8.2</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.8.2</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.9</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.1.3</version>
</dependency>

客户端对象

早起版本的客户端对象已经不推荐使用, 这里使用RestHighLevelClient
这里我用了一个Spring Boot项目直接创建的测试类,但是,奇怪的是,会报错,最后的解决方案是:新建一个空的Maven工程,因为Spring Boot项目里可能会引起jar包冲突。

java.lang.NoSuchMethodError: org.elasticsearch.client.Request.addParameters

索引操作

import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;

import java.io.IOException;

public class ElasticSearchTest {
    public static void main(String[] args) {
        try (RestHighLevelClient restHighLevelClient = new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http")))) {
            {// 创建索引
                CreateIndexRequest createIndexRequest = new CreateIndexRequest("user");
                CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
                System.out.println("操作状态:" + createIndexResponse.isAcknowledged());
            }
            {// 查询索引
                GetIndexRequest getIndexRequest = new GetIndexRequest("user");
                GetIndexResponse getIndexResponse = restHighLevelClient.indices().get(getIndexRequest, RequestOptions.DEFAULT);
                System.out.println("aliases:" + getIndexResponse.getAliases());
                System.out.println("mappings:" + getIndexResponse.getMappings());
                System.out.println("settings:" + getIndexResponse.getSettings());
            }
            {// 删除索引
                DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("user");
                AcknowledgedResponse acknowledgedResponse = restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
                System.out.println("操作结果:" + acknowledgedResponse.isAcknowledged());
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

文档操作

首先创建一个user的索引,用于后续的文档操作,这里写一个demo,把新增文档、修改文档、查询文档、删除文档、批量操作都包含在内。

import net.sf.json.JSONObject;
import org.apache.http.HttpHost;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;

import java.io.IOException;
import java.util.Arrays;

public class ElasticSearchTest {
    public static void main(String[] args) {
        try (RestHighLevelClient restHighLevelClient = new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http")))) {
            {// 新增文档
                IndexRequest indexRequest = new IndexRequest().index("user").id("0001");
                User user = new User("zhangsan", 10, "男");
                String userJSONString = JSONObject.fromObject(user).toString();// 对象转String
                indexRequest.source(userJSONString, XContentType.JSON);// 指定文档数据格式为JSON
                IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
                System.out.println("_index:" + indexResponse.getIndex());
                System.out.println("_id:" + indexResponse.getId());
                System.out.println("_result:" + indexResponse.getResult());
            }
            {// 修改文档
                UpdateRequest updateRequest = new UpdateRequest();
                updateRequest.index("user").id("0001");
                updateRequest.doc(XContentType.JSON, "sex", "女");
                UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
                System.out.println("_index:" + updateResponse.getIndex());
                System.out.println("_id:" + updateResponse.getId());
                System.out.println("_result:" + updateResponse.getResult());
            }
            {// 查询文档
                GetRequest getRequest = new GetRequest().index("user").id("0001");
                GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
                System.out.println("_index:" + getResponse.getIndex());
                System.out.println("_type:" + getResponse.getType());
                System.out.println("_id:" + getResponse.getId());
                System.out.println("source:" + getResponse.getSourceAsString());
            }
            {// 删除文档
                DeleteRequest deleteRequest = new DeleteRequest().index("user").id("0001");
                DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
                System.out.println(deleteResponse.toString());
            }
            {// 批量操作
                {// 批量添加
                    BulkRequest bulkRequest = new BulkRequest();
                    bulkRequest
                            .add(new IndexRequest().index("user").id("0001").source(JSONObject.fromObject(new User("zhangsan", 10, "男")).toString(), XContentType.JSON))
                            .add(new IndexRequest().index("user").id("0002").source(JSONObject.fromObject(new User("lisi", 20, "女")).toString(), XContentType.JSON));
                    BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
                    System.out.println("took:" + bulkResponse.getTook());
                    System.out.println("items:" + Arrays.toString(bulkResponse.getItems()));
                }
                {// 批量删除
                    BulkRequest bulkRequest = new BulkRequest();
                    bulkRequest
                            .add(new DeleteRequest().index("user").id("0001"))
                            .add(new DeleteRequest().index("user").id("0002"));
                    BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
                    System.out.println("took:" + bulkResponse.getTook());
                    System.out.println("items:" + Arrays.toString(bulkResponse.getItems()));
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

高级查询

写一个demo,把请求体查询、高亮查询、聚合查询都包含在内,需要提前准备数据。

import net.sf.json.JSONObject;
import org.apache.http.HttpHost;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.Max;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;

import java.io.IOException;
import java.util.Arrays;

public class ElasticSearchTest {
    public static void main(String[] args) {
        try (RestHighLevelClient restHighLevelClient = new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http")))) {
            {// 准备测试数据
                BulkRequest bulkRequest = new BulkRequest();
                bulkRequest
                        .add(new IndexRequest().index("user").id("0001").source(JSONObject.fromObject(new User("zhangsan", 10, "女")).toString(), XContentType.JSON))
                        .add(new IndexRequest().index("user").id("0002").source(JSONObject.fromObject(new User("lisi", 30, "女")).toString(), XContentType.JSON))
                        .add(new IndexRequest().index("user").id("0003").source(JSONObject.fromObject(new User("wangwu1", 40, "男")).toString(), XContentType.JSON))
                        .add(new IndexRequest().index("user").id("0004").source(JSONObject.fromObject(new User("wangwu2", 20, "女")).toString(), XContentType.JSON))
                        .add(new IndexRequest().index("user").id("0005").source(JSONObject.fromObject(new User("wangwu3", 50, "男")).toString(), XContentType.JSON))
                        .add(new IndexRequest().index("user").id("0006").source(JSONObject.fromObject(new User("wangwu4", 20, "男")).toString(), XContentType.JSON));
                BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
                System.out.println("took:" + bulkResponse.getTook());
                System.out.println("items:" + Arrays.toString(bulkResponse.getItems()));
            }
            {// 请求体查询
                {// 查询所有索引数据
                    SearchRequest searchRequest = new SearchRequest()
                            .indices("user")
                            .source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery()));
                    SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                    SearchHits searchHits = searchResponse.getHits();
                    System.out.println("took:" + searchResponse.getTook());
                    System.out.println("timeout:" + searchResponse.isTimedOut());
                    System.out.println("total:" + searchHits.getTotalHits());
                    System.out.println("MaxScore:" + searchHits.getMaxScore());
                    for (SearchHit searchHit : searchHits) {// 输出每条查询结果
                        System.out.println(searchHit.getSourceAsString());
                    }
                }
                {// term查询,查询条件为关键字
                    SearchRequest searchRequest = new SearchRequest()
                            .indices("user")
                            .source(new SearchSourceBuilder().query(QueryBuilders.termQuery("age", "30")));
                    SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                    SearchHits searchHits = searchResponse.getHits();
                    System.out.println("took:" + searchResponse.getTook());
                    System.out.println("timeout:" + searchResponse.isTimedOut());
                    System.out.println("total:" + searchHits.getTotalHits());
                    System.out.println("MaxScore:" + searchHits.getMaxScore());
                    for (SearchHit searchHit : searchHits) {// 输出每条查询结果
                        System.out.println(searchHit.getSourceAsString());
                    }
                }
                {// 分页查询
                    SearchRequest searchRequest = new SearchRequest()
                            .indices("user")
                            .source(new SearchSourceBuilder()
                                    .query(QueryBuilders.matchAllQuery())
                                    .from(0)// offset
                                    .size(2)// limit
                            );
                    SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                    SearchHits searchHits = searchResponse.getHits();
                    System.out.println("took:" + searchResponse.getTook());
                    System.out.println("timeout:" + searchResponse.isTimedOut());
                    System.out.println("total:" + searchHits.getTotalHits());
                    System.out.println("MaxScore:" + searchHits.getMaxScore());
                    for (SearchHit searchHit : searchHits) {// 输出每条查询结果
                        System.out.println(searchHit.getSourceAsString());
                    }
                }
                {// 数据排序
                    SearchRequest searchRequest = new SearchRequest()
                            .indices("user")
                            .source(new SearchSourceBuilder()
                                            .query(QueryBuilders.matchAllQuery())
                                            .sort("age", SortOrder.ASC)
                                    // 如果有多个字段排序,那就继续指定sort()方法
                            );
                    SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                    SearchHits searchHits = searchResponse.getHits();
                    System.out.println("took:" + searchResponse.getTook());
                    System.out.println("timeout:" + searchResponse.isTimedOut());
                    System.out.println("total:" + searchHits.getTotalHits());
                    System.out.println("MaxScore:" + searchHits.getMaxScore());
                    for (SearchHit searchHit : searchHits) {// 输出每条查询结果
                        System.out.println(searchHit.getSourceAsString());
                    }
                }
                {// 过滤字段
                    SearchRequest searchRequest = new SearchRequest()
                            .indices("user")
                            .source(new SearchSourceBuilder()
                                    .query(QueryBuilders.matchAllQuery())
                                    .fetchSource(new String[]{"name", "age"}, new String[]{"sex"})
                            );
                    SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                    SearchHits searchHits = searchResponse.getHits();
                    System.out.println("took:" + searchResponse.getTook());
                    System.out.println("timeout:" + searchResponse.isTimedOut());
                    System.out.println("total:" + searchHits.getTotalHits());
                    System.out.println("MaxScore:" + searchHits.getMaxScore());
                    for (SearchHit searchHit : searchHits) {// 输出每条查询结果
                        System.out.println(searchHit.getSourceAsString());
                    }
                }
                {// Bool查询
                    SearchRequest searchRequest = new SearchRequest()
                            .indices("user")
                            .source(new SearchSourceBuilder().query(QueryBuilders.boolQuery()
                                    .must(QueryBuilders.matchQuery("age", 20))// 必须满足的条件
                                    .mustNot(QueryBuilders.matchQuery("name", "wangwu2"))// 必须不满足的条件
                                    .should(QueryBuilders.matchQuery("sex", "男"))// 可以满足的条件
                            ));
                    SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                    SearchHits searchHits = searchResponse.getHits();
                    System.out.println("took:" + searchResponse.getTook());
                    System.out.println("timeout:" + searchResponse.isTimedOut());
                    System.out.println("total:" + searchHits.getTotalHits());
                    System.out.println("MaxScore:" + searchHits.getMaxScore());
                    for (SearchHit searchHit : searchHits) {// 输出每条查询结果
                        System.out.println(searchHit.getSourceAsString());
                    }
                }
                {// 范围查询
                    SearchRequest searchRequest = new SearchRequest()
                            .indices("user")
                            .source(new SearchSourceBuilder().query(QueryBuilders.rangeQuery("age")
                                    .gte("20")
                                    .lte("30")));
                    SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                    SearchHits searchHits = searchResponse.getHits();
                    System.out.println("took:" + searchResponse.getTook());
                    System.out.println("timeout:" + searchResponse.isTimedOut());
                    System.out.println("total:" + searchHits.getTotalHits());
                    System.out.println("MaxScore:" + searchHits.getMaxScore());
                    for (SearchHit searchHit : searchHits) {// 输出每条查询结果
                        System.out.println(searchHit.getSourceAsString());
                    }
                }
                {// 模糊查询
                    SearchRequest searchRequest = new SearchRequest()
                            .indices("user")
                            .source(new SearchSourceBuilder().query(QueryBuilders.fuzzyQuery("name", "wangwu")
                                    .fuzziness(Fuzziness.ONE)));
                    SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                    SearchHits searchHits = searchResponse.getHits();
                    System.out.println("took:" + searchResponse.getTook());
                    System.out.println("timeout:" + searchResponse.isTimedOut());
                    System.out.println("total:" + searchHits.getTotalHits());
                    System.out.println("MaxScore:" + searchHits.getMaxScore());
                    for (SearchHit searchHit : searchHits) {// 输出每条查询结果
                        System.out.println(searchHit.getSourceAsString());
                    }
                }
            }
            {// 高亮查询
                SearchRequest searchRequest = new SearchRequest()
                        .indices("user")
                        .source(new SearchSourceBuilder()
                                .query(QueryBuilders.termQuery("name", "zhangsan"))
                                .highlighter(new HighlightBuilder()
                                        .field("name")
                                        .preTags("<font color='red'>")
                                        .postTags("</font>"))
                        );
                SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                SearchHits searchHits = searchResponse.getHits();
                System.out.println("took:" + searchResponse.getTook());
                System.out.println("timeout:" + searchResponse.isTimedOut());
                System.out.println("total:" + searchHits.getTotalHits());
                System.out.println("MaxScore:" + searchHits.getMaxScore());
                for (SearchHit searchHit : searchHits) {// 输出每条查询结果
                    System.out.println(searchHit.getSourceAsString());
                    System.out.println(searchHit.getHighlightFields());
                }
            }
            {// 聚合查询
                {// 最大年龄
                    String maxName = "maxAge";
                    SearchRequest searchRequest = new SearchRequest()
                            .indices("user")
                            .source(new SearchSourceBuilder().aggregation(AggregationBuilders
                                    .max(maxName).field("age"))
                            );
                    SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                    Max max = searchResponse.getAggregations().get(maxName);
                    System.out.println("最大值为:" + max.getValue());
                }
                {// 分组统计
                    String groupName = "groupByAge";
                    SearchRequest searchRequest = new SearchRequest()
                            .indices("user")
                            .source(new SearchSourceBuilder().aggregation(AggregationBuilders
                                    .terms(groupName).field("age"))
                            );
                    SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                    Terms terms = searchResponse.getAggregations().get(groupName);
                    for (Terms.Bucket bucket : terms.getBuckets()) {
                        System.out.println("key=" + bucket.getKeyAsString() + ",count=" + bucket.getDocCount());
                    }
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/656859.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

车载诊断协议 —— 诊断服务Service 11

我是穿拖鞋的汉子,魔都中坚持长期主义的工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 在最艰难的时候,自己就别去幻想太远的将来,只要鼓励自己过好今天就行了! 这世间有太多的猝不及防,有些东西根本不配占有自己的情绪,人生就是一场体验,…

一种栅格数据的空间聚类方法(ACA-Cluster)

本文结合实例详细讲解了如何使用Python对栅格数据进行空间聚类&#xff0c;关注公众号GeodataAnalysis&#xff0c;回复20230616获取示例数据和代码&#xff0c;包含整体的写作思路&#xff0c;上手运行一下代码更容易弄懂。 带有非空间属性的空间数据聚类分析是空间聚类研究的…

English Learning - L3 作业打卡 Lesson6 Day43 2023.6.16 周五

English Learning - L3 作业打卡 Lesson6 Day43 2023.6.16 周五 引言&#x1f349;句1: Thousands of lanterns slowly drift out to sea guiding the dead on their return journey to the other world.成分划分弱读连读爆破语调 &#x1f349;句2: This is a moving spectacl…

炎炎夏日!东南亚LazadaShopee泳衣品类热销榜单来袭

6月商机无限&#xff0c;趁热打铁&#xff01;3大节庆即将来袭。小编特为卖家整理了6月最强爆单选品指南&#xff0c;揭秘东南亚泳衣市场。赶紧一睹为快吧&#xff01; 炎炎夏日&#xff0c;马上即将迎来暑假&#xff0c;海边游玩肯定成了小朋友即家长们的首选之地&#xff0c…

js将json字符串转换为json对象的方法解析

将json字符串转换为json对象的方法。在数据传输过程中&#xff0c;json是以文本&#xff0c;即字符串的形式传递的&#xff0c;而JS操作的是JSON对象&#xff0c;所以&#xff0c;JSON对象和JSON字符串之间的相互转换是关键。 例如&#xff1a; JSON字符串: var str1 ‘{ “n…

MIT 6.S081 Lab Three

MIT 6.S081 Lab Three 引言page tablesPrint a page table (easy)代码解析 A kernel page table per process (hard)代码解析 Simplify copyin/copyinstr&#xff08;hard&#xff09;代码解析 可选的挑战练习 引言 本文为 MIT 6.S081 2020 操作系统 实验三解析。 MIT 6.S081…

shardingsphere第一课-前置课程-Mysql的集群搭建以及多数据源管理

一.Mysql的集群搭建(使用docker搭建省事) 1、关闭防火墙&#xff0c;重启docker** #关闭docker systemctl stop docker #关闭防火墙 systemctl stop firewalld #启动docker systemctl start docker2.1、准备主服务器 解释&#xff1a; 端口号是3306&#xff0c; 指定宿主机配…

FPGA基础知识-时序和延迟

目录 学习目标&#xff1a; 学习内容&#xff1a; 1.延迟模型的类型 2.路径延迟建模 3.时序检查 4.延迟反标注 学习时间&#xff1a; 学习总结 学习目标&#xff1a; 提示&#xff1a;这里可以添加学习目标 鉴别Verilog 仿真中用到的延迟模型的类型&#xff0c;分布延…

YOLOv5改进系列(10)——替换主干网络之GhostNet

【YOLOv5改进系列】前期回顾: YOLOv5改进系列(0)——重要性能指标与训练结果评价及分析 YOLOv5改进系列(1)——添加SE注意力机制

项目中还不会用SpringSecurity,看这篇文章就够了

安全管理是Java应用开发中无法避免的问题&#xff0c;随着Spring Boot和微服务的流行&#xff0c;Spring Security受到越来越多Java开发者的重视&#xff0c;究其原因,还是沾了微服务的光。作为Spring家族中的一员,其在和Spring家族中的其他产品如SpringBoot、Spring Cloud等进…

client-go的Indexer三部曲之而:性能测试

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 本篇概览 本文是《client-go的Indexer》系列的第二篇&#xff0c;在前文咱们通过实例掌握了client-go的Indexer的基本功能&#xff0c;本篇咱们尝试对下面这…

6.pixi.js编写的塔防游戏(类似保卫萝卜)-游戏资源打包逻辑

游戏说明 一个用pixi.js编写的h5塔防游戏&#xff0c;可以用electron打包为exe&#xff0c;支持移动端&#xff0c;也可以用webview控件打包为app在移动端使用 环境说明 cnpm6.2.0 npm6.14.13 node12.22.7 npminstall3.28.0 yarn1.22.10 npm config list electron_mirr…

配置legacyUnhandledExceptionPolicy属性防止处理异常后程序崩溃退出(C#)

这是这篇文章后面遗留的问题&#xff1a; winform中的全局异常信息_winform全局异常捕获_zxy2847225301的博客-CSDN博客 就是线程抛出异常后&#xff0c;被AppDomain.CurrentDomain.UnhandledException注册的事件捕获后&#xff0c;程序依旧崩溃退出。 解决方案&#xff1a;在…

架构-嵌入式模块

章节架构 约三分&#xff0c;主要为选择题 #mermaid-svg-z6RGCDSEQT5AhE1p {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-z6RGCDSEQT5AhE1p .error-icon{fill:#552222;}#mermaid-svg-z6RGCDSEQT5AhE1p .error-text…

【产品经理】从用户体验五要素出发,谈如何设计与体验一款产品

用户体验五要素是产品人必备的知识技能&#xff0c;由于网络碎片化的了解&#xff0c;往往容易造成其高深莫测&#xff0c;晦涩难懂的形象&#xff0c;进而对其束之高阁。但实质不过是一种产品分析与设计的方法论&#xff0c;正确姿势去了解它能帮助我们更好地理解一款产品和从…

移动端小于12px的字体处理方法

今天在按设计稿坐页面时&#xff0c;遇到了下图的情况 ​​​​​ 由于浏览器对字体最小为12px的限制&#xff0c;所以我查阅资料后尝试使用transform:scale来处理 代码如下&#xff1a; <div class"icon"><span class"iconfont icon-a-xuexi3 icon-…

ZYNQ——PL端流水灯的实现

文章目录 一、介绍二、代码编写三、引脚分配四、仿真分析五、添加 ILA IP六、板上验证 一、介绍 本文介绍的是在ZYNQ 7020黑金开发板上实现PL端流水灯的例子&#xff0c;开发板上PL端的LED灯总共有4个&#xff0c;在原理图中找到 PL LED 如下图所示&#xff0c;通过看图可知&a…

【MarkDown】CSDN Markdown之四象限图quadrantChart详解

四象限图 四象限图是一种将数据分为四个象限的可视化方法。它用于在二维网格上绘制数据点&#xff0c;其中一个变量表示x轴&#xff0c;另一个变量表示y轴。根据针对正在分析的数据集的一组标准&#xff0c;将图表分成四个相等的部分来确定四个象限。经常使用四象限图来识别数…

父亲节|祝天下所有父亲节日快乐,长寿安康!

父亲节&#xff0c;是一个感谢父亲的节日。普遍认为的日期是每年6月的第三个星期日&#xff0c;在这一天世界上有52个国家和地区在过父亲节。同时注重孝道也是我们中华民族的传统文化。 在这个感恩的节日里 把最真诚美好的祝福 送给天下所有的父亲们 祝福他们 节日快乐&…

OpenAI 大模型生态

目录标题 1. 语言类大模型2. 图像多模态大模型3. 语音识别模型4. 文本向量化模型5. 审查模型6. 编程大模型1. 语言类大模型 包括GPT-3、GPT-3.5、GPT-4系列模型。并且,OpenAl在训练GPT-3的同时,训练了参数不同、复杂度各不相同的A、B、C、D四项大模型(基座模型),用于不同场景…