REST 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 RESTful。 Web 应用程序最重要的 REST 原则是,客户端和服务器之间的交互在请求之间是无状态的。从客户端到服务器的每个请求都必须包含理解请求所必需的信息。如果服务器在请求之间的任何时间点重启,客户端不会得到通知。此外,无状态请求可以由任何可用服务器回答,这十分适合云计算之类的环境。客户端可以缓存数据以改进性能。
在服务器端,应用程序状态和功能可以分为各种资源。资源是一个有趣的概念实体,它向客户端公开。资源的例子有:应用程序对象、数据库记录、算法等等。每个资源都使用 URI(Universal Resource Identifier) 得到一个唯一的地址。所有资源都共享统一的接口,以便在客户端和服务器之间传输状态。使用的是标准的 HTTP 方法,比如 GET、 PUT、 POST 和DELETE。
在 REST 样式的 Web 服务中,每个资源都有一个地址。资源本身都是方法调用的目
标,方法列表对所有资源都是一样的。这些方法都是标准方法,包括 HTTP GET、 POST、PUT、 DELETE,还可能包括 HEAD 和 OPTIONS。简单的理解就是,如果想要访问互联网上的资源,就必须向资源所在的服务器发出请求,请求体中必须包含资源的网络路径, 以及对资源进行的操作(增删改查)。
REST 样式的 Web 服务若有返回结果,大多数以JSON字符串形式返回。
如果直接通过浏览器向 Elasticsearch 服务器发请求,那么需要在发送的请求中包含
HTTP 标准的方法,而 HTTP 的大部分特性且仅支持 GET 和 POST 方法。所以为了能方便地进行客户端的访问,可以使用 Postman 软件Postman 是一款强大的网页调试工具,提供功能强大的 Web API 和 HTTP 请求调试。
软件功能强大,界面简洁明晰、操作方便快捷,设计得很人性化。 Postman 中文版能够发送任何类型的 HTTP 请求 (GET, HEAD, POST, PUT…),不仅能够表单提交,且可以附带任意类型请求体。
Postman下载页面:https://www.postman.com/downloads/
正排索引(传统)
id | content |
---|---|
1001 | my name is zhang san |
1002 | my name is li si |
倒排索引
keyword | id |
---|---|
name | 1001, 1002 |
zhang | 1001 |
Elasticsearch 是面向文档型数据库,一条数据在这里就是一个文档。 为了方便大家理解,我们将 Elasticsearch 里存储文档数据和关系型数据库 MySQL 存储数据的概念进行一个类比
ES 里的 Index 可以看做一个库,而 Types 相当于表, Documents 则相当于表的行。这里 Types 的概念已经被逐渐弱化, Elasticsearch 6.X 中,一个 index 下已经只能包含一个type, Elasticsearch 7.X 中, Type 的概念已经被删除了。
在 Postman 中,向 ES 服务器发 PUT 请求 : http://127.0.0.1:9200/shopping
结果:
{
"acknowledged": true,//响应结果
"shards_acknowledged": true,//分片结果
"index": "shopping"//索引名称
}
后台日志:
[2021-04-08T13:57:06,954][INFO ][o.e.c.m.MetadataCreateIndexService] [DESKTOP-LNJQ0VF] [shopping] creating index, cause [api], templates [], shards [1]/[1], mappings []
如果重复发 PUT 请求添加索引,因 PUT 具有幂等性,所以会返回错误信息。
{
"error": {
"root_cause": [
{
"type": "resource_already_exists_exception",
"reason": "index [shopping/8uAxOqFuQLm4VTneEWx4sQ] already exists",
"index_uuid": "8uAxOqFuQLm4VTneEWx4sQ",
"index": "shopping"
}
],
"type": "resource_already_exists_exception",
"reason": "index [shopping/8uAxOqFuQLm4VTneEWx4sQ] already exists",
"index_uuid": "8uAxOqFuQLm4VTneEWx4sQ",
"index": "shopping"
},
"status": 400
}
POST 不是幂等的,如果改用 POST,会提示不能使用 POST 。
{
"error": "Incorrect HTTP method for uri [/shopping] and method [POST], allowed: [GET, PUT, HEAD, DELETE]",
"status": 405
}
在 Postman 中,向 ES 服务器发 GET 请求 : http://127.0.0.1:9200/_cat/indices?v
这里请求路径中的_cat 表示查看的意思, indices 表示索引,所以整体含义就是查看当前 ES服务器中的所有索引,就好像 MySQL 中的 show tables 的感觉,服务器响应结果如下 :
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open shopping J0WlEhh4R7aDrfIc3AkwWQ 1 1 0 0 208b 208b
表头 | 含义 |
---|---|
health | 当前服务器健康状态: green(集群完整) yellow(单点正常、集群不完整) red(单点不正常) |
status | 索引打开、关闭状态 |
index | 索引名 |
uuid | 索引统一编号 |
pri | 主分片数量 |
rep | 副本数量 |
docs.count | 可用文档数量 |
docs.deleted | 文档删除状态(逻辑删除) |
store.size | 主分片和副分片整体占空间大小 |
pri.store.size | 主分片占空间大小 |
在 Postman 中,向 ES 服务器发 GET 请求 : http://127.0.0.1:9200/shopping
{
"shopping": {//索引名
"aliases": {},//别名
"mappings": {},//映射
"settings": {//设置
"index": {//设置 - 索引
"creation_date": "1617861426847",//设置 - 索引 - 创建时间
"number_of_shards": "1",//设置 - 索引 - 主分片数量
"number_of_replicas": "1",//设置 - 索引 - 主分片数量
"uuid": "J0WlEhh4R7aDrfIc3AkwWQ",//设置 - 索引 - 主分片数量
"version": {//设置 - 索引 - 主分片数量
"created": "7080099"
},
"provided_name": "shopping"//设置 - 索引 - 主分片数量
}
}
}
}
在 Postman 中,向 ES 服务器发 DELETE 请求 : http://127.0.0.1:9200/shopping
{
"acknowledged": true
}
在 Postman 中,向 ES 服务器发 POST 请求 : http://127.0.0.1:9200/shopping/_doc,将以下数据添加到body中,选中 raw 的 json 格式。
注意,此处发送请求的方式必须为 POST,不能是 PUT,否则会发生错误 。
{
"title":"小米手机",
"category":"小米",
"images":"http://www.gulixueyuan.com/xm.jpg",
"price":3999.00
}
返回结果:
{
"_index": "shopping", //索引
"_type": "_doc", //类型-文档
"_id": "ANQqsHgBaKNfVnMbhZYU", //唯一标识,可以类比为 MySQL 中的主键,随机生成
"_version": 1, //版本
"result": "created", //结果,这里的 create 表示创建成功
"_shards": { //
"total": 2, //分片 - 总数
"successful": 1, //分片 - 总数
"failed": 0 //分片 - 总数
},
"_seq_no": 0,
"_primary_term": 1
}
上面的数据创建后,由于没有指定数据唯一性标识(ID),默认情况下, ES 服务器会随机生成一个。
如果想要自定义唯一性标识,需要在创建时指定: http://127.0.0.1:9200/shopping/_doc/1,请求体JSON内容为:
{
"_index": "shopping",
"_type": "_doc",
"_id": "1", //<------------------自定义唯一性标识
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1
}
此处需要注意:如果增加数据时明确数据主键,那么请求方式也可以为 PUT。
主键查询文档时,需要指明文档的唯一性标识,类似于 MySQL 中数据的主键查询。
在 Postman 中,向 ES 服务器发 GET 请求 : http://127.0.0.1:9200/shopping/_doc/1 。
返回结果如下:
{
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"_version": 1,
"_seq_no": 1,
"_primary_term": 1,
"found": true,
"_source": {
"title": "小米手机",
"category": "小米",
"images": "http://www.gulixueyuan.com/xm.jpg",
"price": 3999
}
}
查找不存在的内容,向 ES 服务器发 GET 请求 : http://127.0.0.1:9200/shopping/_doc/1001。
返回结果如下:
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001",
"found": false
}
查看索引下所有数据,向 ES 服务器发 GET 请求 : http://127.0.0.1:9200/shopping/_search。
返回结果如下:
{
"took": 133,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "ANQqsHgBaKNfVnMbhZYU",
"_score": 1,
"_source": {
"title": "小米手机",
"category": "小米",
"images": "http://www.gulixueyuan.com/xm.jpg",
"price": 3999
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"_score": 1,
"_source": {
"title": "小米手机",
"category": "小米",
"images": "http://www.gulixueyuan.com/xm.jpg",
"price": 3999
}
}
]
}
}
在 Postman 中,向 ES 服务器发 POST 请求 : http://127.0.0.1:9200/shopping/_doc/1 。会将原有的数据内容覆盖。
请求体JSON内容为:
{
"title":"华为手机",
"category":"华为",
"images":"http://www.gulixueyuan.com/hw.jpg",
"price":1999.00
}
修改成功后,服务器响应结果:
{
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"_version": 2,
"result": "updated", //表示数据被更新
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 2,
"_primary_term": 1
}
修改数据时,也可以只修改某一给条数据的局部信息
在 Postman 中,向 ES 服务器发 POST 请求 : http://127.0.0.1:9200/shopping/_update/1。
请求体JSON内容为:
{
"doc": {
"title":"小米手机",
"category":"小米"
}
}
返回结果如下:
{
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"_version": 3,
"result": "updated", //表示数据被更新
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 3,
"_primary_term": 1
}
在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_doc/1,查看修改内容:
{
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"_version": 3,
"_seq_no": 3,
"_primary_term": 1,
"found": true,
"_source": {
"title": "小米手机",
"category": "小米",
"images": "http://www.gulixueyuan.com/hw.jpg",
"price": 1999
}
}
删除一个文档不会立即从磁盘上移除,它只是被标记成已删除(逻辑删除)。
在 Postman 中,向 ES 服务器发 DELETE 请求 : http://127.0.0.1:9200/shopping/_doc/1
返回结果:
{
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"_version": 4,
"result": "deleted", //删除成功
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 4,
"_primary_term": 1
}
查看是否删除成功,发 GET 请求 : http://127.0.0.1:9200/shopping/_doc/1
{
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"found": false
}
查找 category
为 小米
的文档,发送 GET 请求 : http://127.0.0.1:9200/shopping/_search?q=category:小米
。
查找 category
为 小米
的文档,发送 GET请求 : http://127.0.0.1:9200/shopping/_search
,附带JSON体如下:
{
"query":{
"match":{
"category":"小米"
}
}
}
发送 GET 请求 : http://127.0.0.1:9200/shopping/_search
,附带JSON体如下:
{
"query":{
"match_all":{}
}
}
发送 GET请求 : http://127.0.0.1:9200/shopping/_search
,附带JSON体如下:
{
"query":{
"match_all":{}
},
"_source":["title"] //只返回title字段
}
发送 GET 请求 : http://127.0.0.1:9200/shopping/_search
,附带JSON体如下:
{
"query":{
"match_all":{}
},
"from":0, //表示查询开始的下标
"size":2 //表示查询的个数
}
发送 GET 请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:
{
"query":{
"match_all":{}
},
"sort":{
"price":{
"order":"desc" //根据价格进行倒序排序
}
}
}
发送 GET 请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:
{
"query":{
"bool":{
"must":[ //表示and
{
"match":{
"category": "小米"
}
},
{
"match":{
"price": 1999.00
}
}
]
}
}
}
发送 GET 请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:
{
"query":{
"bool":{
"should":[ //表示or
{
"match":{
"category": "小米"
}
},
{
"match":{
"category": "华为"
}
}
]
}
}
}
发送 GET 请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:
{
"query": {
"bool": {
"should": [
{
"match": {
"category": "小米"
}
},
{
"match": {
"category": "华为"
}
}
],
"filter": {
"range": {
"price": {
"gt": 3000
}
}
}
}
}
}
发送 GET 请求 : http://127.0.0.1:9200/shopping/_search。
附带JSON体如下:
{
"query":{
"match":{
"category":"华米"
}
}
}
发送 GET 请求 : http://127.0.0.1:9200/shopping/_search。只能使用字段的子集,才能查询。
{
"query":{
"match_phrase":{
"category":"米"
}
}
}
发送 GET 请求 : http://127.0.0.1:9200/shopping/_search。
{
"query": {
"match_phrase": {
"category": "华为"
}
},
"highlight": {
"fields": {
"category": {}
}
}
}
结果:
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 3.3479528,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "1003",
"_score": 3.3479528,
"_source": {
"title": "华为手机",
"category": "华为",
"images": "http://www.gulixueyuan.com/xm.jpg",
"price": 5999.00
},
"highlight": {
"category": [
"华为"
]
}
}
]
}
}
发送 GET 请求 : http://127.0.0.1:9200/shopping/_search。
{
"aggs": { //聚合操作
"price_group": { //名称,随意起名
"terms": { //分组
"field": "price" //分组字段
}
}
},
"size":0 //不显示原始数据
}
结果:
{
"took": 5,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 6,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"price_group": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 3999.0,
"doc_count": 4
},
{
"key": 1999.0,
"doc_count": 1
},
{
"key": 5999.0,
"doc_count": 1
}
]
}
}
}
发送 GET 请求 : http://127.0.0.1:9200/shopping/_search。
{
"aggs": { //聚合操作
"price_avg": { //名称,随意起名
"avg": { //平均值
"field": "price" //分组字段
}
}
},
"size":0
}
结果:
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 6,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"price_avg": {
"value": 3999.0
}
}
}
参考:es分组后分页_解决 Elastic Search 的深分页问题
https://blog.csdn.net/weixin_32573931/article/details/112418874
search
后加上 scroll=1m
,不能写在 request body
中,其中 1m
表示这个游标要保持开启 1 分钟
hits
里的 hits
会是空 list_scroll_id
,也会回传前 100 笔(假设 size = 100)的数据request body
和一般搜索一样,因此可以说在初始化的过程中,除了加上 scroll 设置游标开启时间之外,其他的都跟一般的搜寻没有两样(要设置查询条件,也会回传前 size 笔的数据)GET http://192.168.1.121:32000/shopping/_search?scroll=1m
{
"_scroll_id": "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAB8WSktlS1p6SHNSSXlfUjhDWURWQjd1dw==",
"took": 181,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "1013",
"_score": 1.0,
"_source": {
"title": "小米手机",
"category": "小米",
"images": "http://www.gulixueyuan.com/xm.jpg",
"price": 5999.00
}
}
]
}
}
使用初始化返回的 _scroll_id
来进行再次请求,每一次请求都会继续返回初始化中未读完数据,并且会返回一个 _scroll_id
,这个 _scroll_id
可能会改变,因此每一次请求应该带上上一次请求返回的 _scroll_id,且每次发送 scroll 请求时,都要在请求参数带上 scroll=1m
,重新刷新这个 scroll
的开启时间,以防不小心超时导致数据取得不完整
注意:返回结果中的字段是 _scroll_id
,但是请求中的字段是 scroll_id
,两者拼写上有不同
GET http://192.168.1.121:32000/_search/scroll?scroll=1m
{
"_scroll_id": "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAAIWR3lwVDJFN2xUQ0NEQWpZMmlVbU1yZw==",
"took": 1,
"timed_out": false,
"terminated_early": true,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 1.0,
"hits": []
}
}
如果没有数据了,就会回传空的 hits,可以用这个判断是否遍历完成了数据
{
"_scroll_id": "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAAIWR3lwVDJFN2xUQ0NEQWpZMmlVbU1yZw==",
"took": 1,
"timed_out": false,
"terminated_early": true,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 1.0,
"hits": []
}
}
在一般场景下,scroll 通常用来取得需要排序过后的大笔数据,但是有时候数据之间的排序性对我们而言是没有关系的,只要所有数据都能取出来就好,这时能够对 scroll 进行优化
请求初始化
使用 _doc 去 sort 得出来的结果,这个执行的效率最快,但是数据就不会有排序,适合用在只想取得所有数据的场景
GET http://192.168.1.121:32000/shopping/_search?scroll=1m
{
"query": {
"match_all" : {}
},
"sort": ["_doc"]
}
虽然我们在设置开启 scroll 时,设置了一个 scroll 的存活时间,但是如果能够在使用完顺手关闭,可以提早释放资源,降低 ES 的负担
DELETE _search/scroll
{
"scroll_id": "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAAIWR3lwVDJFN2xUQ0NEQWpZMmlVbU1yZw=="
}
接下来就需要建索引库(index)中的映射了,类似于数据库(database)中的表结构(table)。
创建数据库表需要设置字段名称,类型,长度,约束等;索引库也一样,需要知道这个类型下有哪些字段,每个字段有哪些约束信息,这就叫做映射(mapping)。
PUT http://127.0.0.1:9200/user
# PUT http://127.0.0.1:9200/user/_mapping
{
"properties": {
"name":{
"type": "text",
"index": true
},
"sex":{
"type": "keyword",
"index": true
},
"tel":{
"type": "keyword",
"index": false
}
}
}
GET http://127.0.0.1:9200/user/_mapping
结果
{
"user": {
"mappings": {
"properties": {
"name": {
"type": "text"
},
"sex": {
"type": "keyword"
},
"tel": {
"type": "keyword",
"index": false
}
}
}
}
}
#PUT http://127.0.0.1:9200/user/_create/1001
{
"name":"小米",
"sex":"男的",
"tel":"1111"
}
结果
{
"_index": "user",
"_type": "_doc",
"_id": "1001",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
#GET http://127.0.0.1:9200/user/_search
{
"query":{
"match":{
"name":"小"
}
}
}
结果:
{
"took": 495,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.2876821,
"hits": [
{
"_index": "user",
"_type": "_doc",
"_id": "1001",
"_score": 0.2876821,
"_source": {
"name": "小米",
"sex": "男的",
"tel": "1111"
}
}
]
}
}
#GET http://127.0.0.1:9200/user/_search
{
"query":{
"match":{
"sex":"男"
}
}
}
结果:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 0,
"relation": "eq"
},
"max_score": null,
"hits": []
}
}
找不想要的结果,只因创建映射时"sex"的类型为"keyword"。
"sex"只能完全为”男的“,才能得出原数据。
#GET http://127.0.0.1:9200/user/_search
{
"query":{
"match":{
"sex":"男的"
}
}
}
结果
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.2876821,
"hits": [
{
"_index": "user",
"_type": "_doc",
"_id": "1001",
"_score": 0.2876821,
"_source": {
"name": "小米",
"sex": "男的",
"tel": "1111"
}
}
]
}
}
报错只因创建映射时"tel"的"index"为false。
# GET http://127.0.0.1:9200/user/_search
{
"query":{
"match":{
"tel":"11"
}
}
}
{
"error": {
"root_cause": [
{
"type": "query_shard_exception",
"reason": "failed to create query: Cannot search on field [tel] since it is not indexed.",
"index_uuid": "ivLnMfQKROS7Skb2MTFOew",
"index": "user"
}
],
"type": "search_phase_execution_exception",
"reason": "all shards failed",
"phase": "query",
"grouped": true,
"failed_shards": [
{
"shard": 0,
"index": "user",
"node": "4P7dIRfXSbezE5JTiuylew",
"reason": {
"type": "query_shard_exception",
"reason": "failed to create query: Cannot search on field [tel] since it is not indexed.",
"index_uuid": "ivLnMfQKROS7Skb2MTFOew",
"index": "user",
"caused_by": {
"type": "illegal_argument_exception",
"reason": "Cannot search on field [tel] since it is not indexed."
}
}
}
]
},
"status": 400
}
新建Maven工程。
添加依赖:
<dependencies>
<dependency>
<groupId>org.elasticsearchgroupId>
<artifactId>elasticsearchartifactId>
<version>7.8.0version>
dependency>
<dependency>
<groupId>org.elasticsearch.clientgroupId>
<artifactId>elasticsearch-rest-clientartifactId>
<version>7.8.0version>
dependency>
<dependency>
<groupId>org.elasticsearch.clientgroupId>
<artifactId>elasticsearch-rest-high-level-clientartifactId>
<version>7.8.0version>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-apiartifactId>
<version>2.8.2version>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-coreartifactId>
<version>2.8.2version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.9.9version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
dependencies>
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import java.io.IOException;
public class HelloElasticsearch {
public static void main(String[] args) throws IOException {
// 创建客户端对象
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(new HttpHost("192.168.1.115", 9200, "http")));
// ...
System.out.println(client);
// 关闭客户端连接
client.close();
}
}
package index;
import org.apache.http.HttpHost;
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 java.io.IOException;
/**
* 创建Index
*/
public class CreateIndex {
public static void main(String[] args) throws IOException {
// 创建客户端对象
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(new HttpHost("192.168.1.115", 9200, "http")));
// 创建索引 - 请求对象
CreateIndexRequest request = new CreateIndexRequest("user3");
// 发送请求,获取响应
CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
boolean acknowledged = response.isAcknowledged();
// 响应状态
System.out.println("操作状态 = " + acknowledged);
// 关闭客户端连接
client.close();
}
}
package index;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
import java.io.IOException;
/**
* 查询索引
*/
public class SearchIndex {
public static void main(String[] args) throws IOException {
// 创建客户端对象
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(new HttpHost("192.168.1.115", 9200, "http")));
// 查询索引 - 请求对象
GetIndexRequest request = new GetIndexRequest("user3");
// 发送请求,获取响应
GetIndexResponse response = client.indices().get(request, RequestOptions.DEFAULT);
System.out.println("aliases:" + response.getAliases());
System.out.println("mappings:" + response.getMappings());
System.out.println("settings:" + response.getSettings());
client.close();
}
}
package index;
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 java.io.IOException;
/**
* 删除索引
*/
public class DeleteIndex {
public static void main(String[] args) throws IOException {
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(new HttpHost("192.168.1.115", 9200, "http")));
// 删除索引 - 请求对象
DeleteIndexRequest request = new DeleteIndexRequest("user3");
// 发送请求,获取响应
AcknowledgedResponse response = client.indices().delete(request, RequestOptions.DEFAULT);
// 操作结果
System.out.println("操作结果 : " + response.isAcknowledged());
client.close();
}
}
在进行文档操作前,需要先添加以下两个类,ES任务接口和ES任务执行器。
ES任务接口
package base;
import org.elasticsearch.client.RestHighLevelClient;
/**
* ES任务接口
*/
public interface ESTask {
void doing(RestHighLevelClient client) throws Exception;
}
ES任务执行器
package base;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
public class ES {
public static void doing(ESTask task) {
// 创建客户端对象
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(new HttpHost("192.168.1.115", 9200, "http")));
try {
task.doing(client);
// 关闭客户端连接
client.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
package doc;
import base.ESTask;
import com.fasterxml.jackson.databind.ObjectMapper;
import base.ES;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.common.xcontent.XContentType;
import po.User;
/**
* 添加文档信息
*/
public class InsertDoc {
private static ESTask insertTask = client -> {
// 新增文档 - 请求对象
IndexRequest request = new IndexRequest();
// 设置索引及唯一性标识
request.index("user").id("1001");
// 创建数据对象
User user = new User();
user.setName("zhangsan");
user.setAge(30);
user.setSex("男");
ObjectMapper objectMapper = new ObjectMapper();
String productJson = objectMapper.writeValueAsString(user);
System.out.println(productJson);
// 添加文档数据,数据格式为 JSON 格式
request.source(productJson, XContentType.JSON);
// 客户端发送请求,获取响应对象
IndexResponse response = client.index(request, RequestOptions.DEFAULT);
//3.打印结果信息
System.out.println("_index:" + response.getIndex());
System.out.println("_id:" + response.getId());
System.out.println("_result:" + response.getResult());
};
public static void main(String[] args) {
//执行
ES.doing(insertTask);
}
}
package doc;
import base.ES;
import base.ESTask;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.client.RequestOptions;
/**
* 获取文档信息
*/
public class GetDoc {
static ESTask getDocTask = client -> {
//1.创建请求对象
GetRequest request = new GetRequest().index("user").id("1001");
//2.客户端发送请求,获取响应对象
GetResponse response = client.get(request, RequestOptions.DEFAULT);
//3.打印结果信息
System.out.println("_index:" + response.getIndex());
System.out.println("_type:" + response.getType());
System.out.println("_id:" + response.getId());
System.out.println("source:" + response.getSourceAsString());
};
public static void main(String[] args) {
ES.doing(getDocTask);
}
}
package doc;
import base.ES;
import base.ESTask;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.common.xcontent.XContentType;
/**
* 更新文档信息
*/
public class UpdateDoc {
static ESTask updateDocTask = client -> {
// 修改文档 - 请求对象
UpdateRequest request = new UpdateRequest();
// 配置修改参数
request.index("user").id("1001");
// 设置请求体,对数据进行修改
request.doc(XContentType.JSON, "sex", "女");
// 客户端发送请求,获取响应对象
UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
System.out.println("_index:" + response.getIndex());
System.out.println("_id:" + response.getId());
System.out.println("_result:" + response.getResult());
};
public static void main(String[] args) {
ES.doing(updateDocTask);
}
}
package doc;
import base.ES;
import base.ESTask;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.client.RequestOptions;
/**
* 删除文档信息
*/
public class DeleteDoc {
static ESTask deleteDocTask = client -> {
//创建请求对象
DeleteRequest request = new DeleteRequest().index("user").id("1001");
//客户端发送请求,获取响应对象
DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);
//打印信息
System.out.println(response.toString());
};
public static void main(String[] args) {
ES.doing(deleteDocTask);
}
}
package doc;
import base.ESTask;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.query.TermsQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import java.util.Map;
/**
* 查询任务
*/
public class QueryDocTask {
/**
* 简单查询
*/
static ESTask simpleQueryDoc = client -> {
SearchRequest request = new SearchRequest();
request.indices("user");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchAllQuery());
request.source(sourceBuilder);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//输出结果
printResponse(response);
};
/**
* 条件查询
*/
static ESTask conditionQueryDoc = client -> {
SearchRequest request = new SearchRequest();
request.indices("user");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.termQuery("age", "30"));
request.source(sourceBuilder);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//输出结果
printResponse(response);
};
/**
* 分页查询
*/
static ESTask pageQueryDoc = client -> {
SearchRequest request = new SearchRequest();
request.indices("user");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchAllQuery());
// 当前页其实索引(第一条数据的顺序号), from
sourceBuilder.from(0);
// 每页显示多少条 size
sourceBuilder.size(2);
request.source(sourceBuilder);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//输出结果
printResponse(response);
};
/**
* 查询排序
*/
static ESTask sortQueryDoc = client -> {
SearchRequest request = new SearchRequest();
request.indices("user");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchAllQuery());
sourceBuilder.sort("age", SortOrder.ASC);
request.source(sourceBuilder);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//输出结果
printResponse(response);
};
/**
* 查询过滤
*/
static ESTask fetchQueryDoc = client -> {
SearchRequest request = new SearchRequest();
request.indices("user");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchAllQuery());
String[] includes = {};
String[] excludes = {"age"};
sourceBuilder.fetchSource(includes, excludes);
request.source(sourceBuilder);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//输出结果
printResponse(response);
};
/**
* 组合查询
*/
static ESTask composeQueryDoc = client -> {
SearchRequest request = new SearchRequest();
request.indices("user");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
// 必须包含
boolQueryBuilder.must(QueryBuilders.matchQuery("age", "30"));
// 一定不含
boolQueryBuilder.mustNot(QueryBuilders.matchQuery("name", "zhangsan"));
// 可能包含
boolQueryBuilder.should(QueryBuilders.matchQuery("sex", "女"));
sourceBuilder.query(boolQueryBuilder);
request.source(sourceBuilder);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//输出结果
printResponse(response);
};
/**
* 范围查询
*/
static ESTask rangeQueryDoc = client -> {
SearchRequest request = new SearchRequest();
request.indices("user");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("age");
//大于等于30
rangeQuery.gte("30");
//小于50
rangeQuery.lt("50");
sourceBuilder.query(rangeQuery);
request.source(sourceBuilder);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//输出结果
printResponse(response);
};
/**
* 模糊查询
*/
static ESTask fuzzyQueryDoc = client -> {
SearchRequest request = new SearchRequest();
request.indices("user");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//Fuzziness.ONE 表示可以相差一位字符
sourceBuilder.query(QueryBuilders.fuzzyQuery("name", "wangwu").fuzziness(Fuzziness.ONE));
request.source(sourceBuilder);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//输出结果
printResponse(response);
};
/**
* 高亮查询
*/
static ESTask highlightQueryDoc = client -> {
SearchRequest request = new SearchRequest();
request.indices("user");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery("name", "zhangsan");
sourceBuilder.query(termsQueryBuilder);
//构建高亮字段
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.preTags("");//设置标签前缀
highlightBuilder.postTags("");//设置标签后缀
highlightBuilder.field("name");//设置高亮字段
//设置高亮构建对象
sourceBuilder.highlighter(highlightBuilder);
request.source(sourceBuilder);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//输出结果
printResponse(response);
};
/**
* 最大值查询
*/
static ESTask maxQueryDoc = client -> {
SearchRequest request = new SearchRequest();
request.indices("user");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.aggregation(AggregationBuilders.max("maxAge").field("age"));
request.source(sourceBuilder);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//输出结果
//printResponse(response);
System.out.println(response);
};
/**
* 分组查询
*/
static ESTask groupQueryDoc = client -> {
SearchRequest request = new SearchRequest();
request.indices("user");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.aggregation(AggregationBuilders.terms("age_group").field("age"));
request.source(sourceBuilder);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//输出结果
//printResponse(response);
System.out.println(response);
};
/**
* 打印结果
*
* @param response
*/
private static void printResponse(SearchResponse response) {
SearchHits hits = response.getHits();
System.out.println("took:" + response.getTook());
System.out.println("timeout:" + response.isTimedOut());
System.out.println("total:" + hits.getTotalHits());
System.out.println("MaxScore:" + hits.getMaxScore());
System.out.println("hits========>>");
for (SearchHit hit : hits) {
//输出每条查询的结果信息
System.out.println(hit.getSourceAsString());
//打印高亮结果
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
if (highlightFields.size() > 0)
System.out.println(highlightFields);
}
System.out.println("<<========");
}
}
package doc;
import base.ES;
/**
* 文档查询
*/
public class QueryDoc {
public static void main(String[] args) {
//简单查询
ES.doing(QueryDocTask.simpleQueryDoc);
//条件查询
ES.doing(QueryDocTask.conditionQueryDoc);
//分页查询
ES.doing(QueryDocTask.conditionQueryDoc);
//排序
ES.doing(QueryDocTask.conditionQueryDoc);
//过滤查询
ES.doing(QueryDocTask.conditionQueryDoc);
//组合查询
ES.doing(QueryDocTask.conditionQueryDoc);
//范围查询
ES.doing(QueryDocTask.conditionQueryDoc);
//模糊查询
ES.doing(QueryDocTask.conditionQueryDoc);
//高亮查询
ES.doing(QueryDocTask.conditionQueryDoc);
//最大值查询
ES.doing(QueryDocTask.conditionQueryDoc);
//分组查询
ES.doing(QueryDocTask.conditionQueryDoc);
}
}