ElasticSearch
将需要存储的数据分为:结构化数据、非结构化数据、半结构化数据
结构化数据 一般为二维的表结构,比如一张表包含了用户的姓名性别年龄等信息。(一般保存到关系型数据库中,如 MySQL)
非结构化数据 是无法用二维表结构表现数据的一种数据,比如服务器日志、工作文档、报表、视频音频图片等。(一般保存到 NOSQL 数据库中,如 Redis、HBASE(以 key、value 结构保存数据))
半结构化数据 是将数据的结构和内容混在一起,比如 xml 文件、html 文件(一般保存到 NOSQL 数据库中,如 Redis、HBASE(以 key、value 结构保存数据))
Elastic Stack 包括 Elasticserarch、Kibana、Beats、Logstash
ES 能够安全可靠地获取任何来源、任何格式的数据,然后实时的对数据进行搜索、分析和可视化。
ES 是一个开源的高扩展的分布式全文搜索引擎,可以近乎实时的存储、检索数据,本身扩展性很好,可以扩展到上百台服务器,处理 PB 级别的数据。
数据的发送和数据的接收都是以 JSON 的格式进行的。
一、索引操作
1)创建索引
对比关系型数据库,创建索引就等同于创建数据库
PUT:http://127.0.0.1:9200/shopping -- 创建一个名字叫做 shopping 的索引(PUT 请求表示创建的意思)
同样的请求发送多次会报错,因为 PUT 请求是幂等性的。
响应结果为:
{
"acknowledged": true, // 表示这个索引创建成功
"shards_acknowledged": true,
"index": "shopping" // 索引的名字叫做 shopping
}
2)查看刚刚创建的索引
GET:http://127.0.0.1:9200/shopping -- 获取索引的相关信息(GET 请求表示获取的意思)
响应结果为:
{
"shopping": {
"aliases": {},
"mappings": {},
"settings": {
"index": {
"creation_date": "1647422584193",
"number_of_shards": "1",
"number_of_replicas": "1",
"uuid": "BMzmeykyTvmFo8OGOrp8lw",
"version": {
"created": "7080099"
},
"provided_name": "shopping"
}
}
}
}
3)查看所有的索引
GET:http://127.0.0.1:9200/_cat/indices?v -- 获取 ES 服务器中的所有索引的相关信息(GET 请求表示获取的意思)
响应结果为:(当前就只有一个索引)
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open shopping BMzmeykyTvmFo8OGOrp8lw 1 1 0 0 208b 208b
4)删除索引
DELETE:http://127.0.0.1:9200/shopping -- 删除 shopping 索引(DELETE 请求表示删除的意思)
响应结果为:
{
"acknowledged": true // 表示这个操作执行成功
}
二、文档操作
文档就是数据。向索引中添加数据。在 MySQL 中添加数据需要先创建表,然后再向表中添加数据,而 ES 中没有表的概念,所以向 ES 中添加数据,就是直接向索引中添加数据。
1)创建文档(id 随机生成)
POST:http://127.0.0.1:9200/shopping/_doc -- 向 shopping 索引中添加文档(数据)(POST 请求表示向服务器添加数据的意思)
同样的请求发送多次不会报错,因为 POST 请求不是幂等性的。
需要在请求体中传入数据信息:
{
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
响应结果为:
{
"_index": "shopping",
"_type": "_doc",
"_id": "Ttatkn8BWzMOMKEQR5zC", // 随机生成的id
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
"_id": "Ttatkn8BWzMOMKEQR5zC" -- id 属性,表示这条数据的唯一标识(随机生成的),类似于主键。所以同样的请求,发送多次,返回的结果是不一样的,也就是添加了多条数据,只不过每条数据的内容是一样的,id 不一样。
2)创建文档(id自定义-使用POST)
随机生成的 id 不容易记,可以采用自己的方式定义 id,只需要在请求路径的最后写上自定义的 id。
POST:http://127.0.0.1:9200/shopping/_doc/1001 -- 向 shopping 索引中添加自定义 id 的文档(数据)(POST 请求表示向服务器添加数据的意思)
这种情况下相同的数据发送多次,返回的结果都是相同的,这就是一个幂等性的操作。
需要在请求体中传入数据信息:
{
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
响应结果为:
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001", // 自己定义的id
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1
}
3)创建文档(id 自定义- 使用 PUT)
随机生成的 id 不容易记,可以采用自己的方式定义 id,只需要在请求路径的最后写上自定义的 id。
PUT:http://127.0.0.1:9200/shopping/_doc/1002 -- 向 shopping 索引中添加自定义 id 的文档(数据)(幂等性操作下使用 PUT 请求也可以向服务器添加数据)
需要在请求体中传入数据信息:
{
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
响应结果为:
{
"_index": "shopping",
"_type": "_doc",
"_id": "1002", // 自己定义的id
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 4,
"_primary_term": 1
}
4)创建文档(id 自定义- 使用 PUT)
为了表示操作为创建数据,可以将 _doc 换成自定义的 _create,用来标明这是创建数据的过程。
PUT:http://127.0.0.1:9200/shopping/_create/1003 -- 向 shopping 索引中添加自定义 id 的文档(数据)(幂等性操作下使用 PUT 请求也可以向服务器添加数据)
需要在请求体中传入数据信息:
{
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
响应结果为:
{
"_index": "shopping",
"_type": "_doc", // 表示文档数据的意思
"_id": "1003",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 5,
"_primary_term": 1
}
三、数据操作
1、查询数据
1)查询指定的一条数据
GET:http://127.0.0.1:9200/shopping/_doc/1001 -- 查询指定的一条数据
响应结果为:
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001",
"_version": 3,
"_seq_no": 3,
"_primary_term": 1,
"found": true, // 代表查询成功
"_source": {
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
}
2)查询所有数据
GET:http://127.0.0.1:9200/shopping/_search -- 查询所有数据
响应结果为:
{
"took": 73,
"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": "Ttatkn8BWzMOMKEQR5zC",
"_score": 1.0,
"_source": {
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1002",
"_score": 1.0,
"_source": {
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001",
"_score": 1.0,
"_source": {
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1003",
"_score": 1.0,
"_source": {
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
}
]
}
}
2、修改数据
1)完全覆盖性修改
完全性覆盖意味着不论发送多少次请求,数据每次都会完全被覆盖。这就是幂等性操作,可以使用 PUT 进行操作。
PUT:http://127.0.0.1:9200/shopping/_doc/1001 -- 修改文档 _doc 中的数据
需要在请求体中传入数据信息:
{
"title": "荣耀手机",
"category": "荣耀",
"images": "http://www.baidu.com/rongyao.jpg",
"price": 3888.00
}
响应结果为:
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001",
"_version": 4,
"result": "updated", // 代表修改成功
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 6,
"_primary_term": 1
}
再进行 GET:http://127.0.0.1:9200/shopping/_doc/1001 查询时就显示刚刚修改的数据。
2)局部性修改
只更新局部的数据,每一次更新操作,返回的结果都是不相同的,那么就不是幂等性操作,就要使用 POST 方式。
POST:http://127.0.0.1:9200/shopping/_update/1001 -- 修改文档 _doc 中的 id 为 1001 的数据的 title 为 荣耀50Pro
需要在请求体中传入数据信息:
{
"doc": {
"title": "荣耀50Pro"
}
}
响应结果为:
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001",
"_version": 5,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 7,
"_primary_term": 1
}
再进行 GET:http://127.0.0.1:9200/shopping/_doc/1001 查询时就显示刚刚修改的数据。
3、删除数据
DELETE:http://127.0.0.1:9200/shopping/_doc/1001 -- 删除数据
响应结果为:
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001",
"_version": 6,
"result": "deleted", // 代表删除成功
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 8,
"_primary_term": 1
}
四、复杂查询
1、条件查询
1)条件查询(条件在请求路径中)
GET:http://127.0.0.1:9200/shopping/_search?q=category:华为 -- 查询所有 category=华为 的数据(? 表示在后面拼接查询条件,q 是 query 的意思,表示查询)
响应结果为:
{
"took": 38,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 0.21072102,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "Ttatkn8BWzMOMKEQR5zC",
"_score": 0.21072102,
"_source": {
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1002",
"_score": 0.21072102,
"_source": {
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1003",
"_score": 0.21072102,
"_source": {
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
}
]
}
}
但是这种方式是把参数直接写在请求路径中,并且有中文,容易出现乱码问题,下面这种方式是把请求参数放在请求体中。
2)条件查询(条件在请求体中)
GET:http://127.0.0.1:9200/shopping/_search -- 查询所有 category=华为 的数据
需要在请求体中传入数据信息:
{
"query": { // 表示查询
"match": { // 表示匹配查询
"category": "华为"
}
}
}
响应结果为:
{
"took": 13,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 0.21072102,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "Ttatkn8BWzMOMKEQR5zC",
"_score": 0.21072102,
"_source": {
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1002",
"_score": 0.21072102,
"_source": {
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1003",
"_score": 0.21072102,
"_source": {
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
}
]
}
}
推荐使用这种在请求体中添加查询条件的方式
3)条件查询(完全匹配查询)
GET:http://127.0.0.1:9200/shopping/_search -- 查询所有 category=华 或者 category=为 的数据
需要在请求体中传入数据信息:
{
"query": {
"match": {
"category": "华为"
}
}
}
在入参中的 category 中,传入“华为”、“华”、“为”,返回的结果都是一样的,这是因为当保存文档数据时,ES 会将数据文字进行分词拆解操作,并将拆解后的数据保存到倒排索引当中,这样即使使用文字的一部分也能查询到数据,这种检索方式就是全文检索。
如果完全比配的话,就需要将 match 改成 match_phrase
需要在请求体中传入数据信息:
{
"query": {
"match_phrase": { // 表示完全匹配
"category": "华荣"
}
}
}
此时返回结果为空,因为 ES 中没有 category 为 “华荣” 的数据,这是进行的完全匹配。
将匹配的内容高亮显示:
需要在请求体中传入数据信息:
{
"query": {
"match": {
"category": "荣耀"
}
},
"highlight": { // 表示高亮
"fields": { // 表示对哪些元素高亮
"category": {}
}
}
}
响应结果为:
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": 2.2699597,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001",
"_score": 2.2699597,
"_source": {
"title": "华为手机111",
"category": "荣耀",
"images": "http://www.baidu.com/huawei111.jpg",
"price": 1111.11
},
"highlight": {
"category": [
"<em>荣</em><em>耀</em>"
]
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1002",
"_score": 2.2699597,
"_source": {
"title": "华为手机",
"category": "荣耀",
"images": "http://www.baidu.com/huawei.jpg",
"price": 2222.22
},
"highlight": {
"category": [
"<em>荣</em><em>耀</em>"
]
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1003",
"_score": 2.2699597,
"_source": {
"title": "华为手机",
"category": "荣耀",
"images": "http://www.baidu.com/huawei.jpg",
"price": 3333.33
},
"highlight": {
"category": [
"<em>荣</em><em>耀</em>"
]
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1004",
"_score": 2.2699597,
"_source": {
"title": "华为手机444",
"category": "荣耀",
"images": "http://www.baidu.com/huawei444.jpg",
"price": 4444.44
},
"highlight": {
"category": [
"<em>荣</em><em>耀</em>"
]
}
}
]
}
}
4)条件查询(查询所有数据)
GET:http://127.0.0.1:9200/shopping/_search -- 查询所有数据
需要在请求体中传入数据信息:
{
"query": { // 表示查询
"match_all": { // 表示匹配所有
}
}
}
响应结果为:
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "Ttatkn8BWzMOMKEQR5zC",
"_score": 1.0,
"_source": {
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1002",
"_score": 1.0,
"_source": {
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1003",
"_score": 1.0,
"_source": {
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
}
]
}
}
2、分页查询
先再增加几条数据。
1)分页查询详细数据
GET:http://127.0.0.1:9200/shopping/_search -- 分页查询详细数据
需要在请求体中传入数据信息:
{
"query": {
"match_all": {
}
},
"from": 0, // 表示当前页数据的起始位置(如果是第一条数据,from的值是0)
"size": 3 // 表示每页显示的数据条数
}
起始页 =(页码 - 1)* 每页数据条数 -- 就是说如果想查询第 3 页的数据,from = (3-1)*size = 6
响应结果为:
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 9,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "Ttatkn8BWzMOMKEQR5zC",
"_score": 1.0,
"_source": {
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1002",
"_score": 1.0,
"_source": {
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1003",
"_score": 1.0,
"_source": {
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
}
]
}
}
2)分页查询想要的数据
GET:http://127.0.0.1:9200/shopping/_search -- 分页查询想要的字段的数据
需要在请求体中传入数据信息:
{
"query": {
"match_all": {
}
},
"from": 0,
"size": 3,
"_source": ["title"] // 表示只查询出数据的title字段值
}
响应结果为:
{
"took": 8,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 9,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "Ttatkn8BWzMOMKEQR5zC",
"_score": 1.0,
"_source": {
"title": "华为手机"
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1002",
"_score": 1.0,
"_source": {
"title": "华为手机"
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1003",
"_score": 1.0,
"_source": {
"title": "华为手机"
}
}
]
}
}
3)分页查询想要的数据并排序
先将之前的数据的 price 修改一下,方便排序查看效果。
GET:http://127.0.0.1:9200/shopping/_search -- 分页查询想要的字段的数据并且进行排序
需要在请求体中传入数据信息:
{
"query": {
"match_all": {
}
},
"from": 0,
"size": 3,
"_source": ["title"],
"sort": { // 表示排序
"price": { // 表示按照price字段进行排序
"order": "asc" // 表示按照升序还是降序排序
}
}
}
响应结果为:
{
"took": 26,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 9,
"relation": "eq"
},
"max_score": null,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001",
"_score": null,
"_source": {
"title": "华为手机111"
},
"sort": [
1111.11
]
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1002",
"_score": null,
"_source": {
"title": "华为手机"
},
"sort": [
2222.22
]
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1003",
"_score": null,
"_source": {
"title": "华为手机"
},
"sort": [
3333.33
]
}
]
}
}
3、多条件组合查询
1)must 多条件同时成立
GET:http://127.0.0.1:9200/shopping/_search -- 查询同时满足多个条件的数据
需要在请求体中传入数据信息:
{
"query": { // 表示查询
"bool": { // 表示条件
"must": [ // 表示多个条件同时成立,类似于and(查询出category是华为、price为8888.88的数据)
{
"match": {
"category": "华为"
}
},
{
"match": {
"price": 8888.88
}
}
]
}
}
}
响应结果为:
{
"took": 23,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.0727353,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "1008",
"_score": 1.0727353,
"_source": {
"title": "华为手机888",
"category": "华为",
"images": "http://www.baidu.com/huawei888.jpg",
"price": 8888.88
}
}
]
}
}
2)should 多条件任意一个成立
GET:http://127.0.0.1:9200/shopping/_search -- 查询满足任意一个条件的数据
需要在请求体中传入数据信息:
{
"query": { // 表示查询
"bool": { // 表示条件
"should": [ // 表示多个条件任何一个成立即可,类似于or(查询出price为6666.66或者price为8888.88的数据)
{
"match": {
"price": 6666.66
}
},
{
"match": {
"price": 8888.88
}
}
]
}
}
}
响应结果为:
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "1008",
"_score": 1.0,
"_source": {
"title": "华为手机888",
"category": "华为",
"images": "http://www.baidu.com/huawei888.jpg",
"price": 8888.88
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1006",
"_score": 1.0,
"_source": {
"title": "华为手机666",
"category": "华为",
"images": "http://www.baidu.com/huawei666.jpg",
"price": 6666.66
}
}
]
}
}
3)should 多条件查询带过滤
GET:http://127.0.0.1:9200/shopping/_search -- 查询满足任意一个条件的数据,并进行过滤
需要在请求体中传入数据信息:
{
"query": {
"bool": {
"should": [
{
"match": {
"price": 3333.33
}
},
{
"match": {
"price": 6666.66
}
},
{
"match": {
"price": 8888.88
}
}
],
"filter": { // 表示一个过滤器,根据条件把查询出来的结果再进行过滤
"range": { // 表示过滤的范围
"price": { // 表示按照price进行过滤
"gt": 5000 // 表示按照price大于5000进行过滤
}
}
}
}
}
}
响应结果为:
{
"took": 10,
"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": "1008",
"_score": 1.0,
"_source": {
"title": "华为手机888",
"category": "华为",
"images": "http://www.baidu.com/huawei888.jpg",
"price": 8888.88
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1006",
"_score": 1.0,
"_source": {
"title": "华为手机666",
"category": "华为",
"images": "http://www.baidu.com/huawei666.jpg",
"price": 6666.66
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1007",
"_score": 0.0,
"_source": {
"title": "华为手机777",
"category": "华为",
"images": "http://www.baidu.com/huawei777.jpg",
"price": 7777.77
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1005",
"_score": 0.0,
"_source": {
"title": "华为手机555",
"category": "华为",
"images": "http://www.baidu.com/huawei555.jpg",
"price": 5555.55
}
}
]
}
}
会发现这种情况并没有返回想要的数据,不加过滤器 filter 之前应该返回 price 为 3333.33 和 price 为 6666.66 和 price 为 8888.88 这三条数据,加了过滤器 filter 之后返回的数据应该在这三条数据中筛选出 price 大于 5000 的数据,也就是返回 price 为 6666.66 和 price 为 8888.88 这两条数据,但是实际返回结果却是 price 大于 5000 的所有数据。
这是因为在使用 should 查询时,如果包含了 must 或者 filter 查询,那么 should 的作用就失效了。解决办法是:
在请求体中加上:"minimum_should_match": 1
需要在请求体中传入数据信息:
{
"query": {
"bool": {
"should": [
{
"match": {
"price": 3333.33
}
},
{
"match": {
"price": 6666.66
}
},
{
"match": {
"price": 8888.88
}
}
],
"filter": {
"range": {
"price": {
"gt": 5000
}
}
},
"minimum_should_match": 1 // 解决should失效问题
}
}
}
响应结果为:
{
"took": 9,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "1008",
"_score": 1.0,
"_source": {
"title": "华为手机888",
"category": "华为",
"images": "http://www.baidu.com/huawei888.jpg",
"price": 8888.88
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1006",
"_score": 1.0,
"_source": {
"title": "华为手机666",
"category": "华为",
"images": "http://www.baidu.com/huawei666.jpg",
"price": 6666.66
}
}
]
}
}
4、对查询结果进行聚合操作
1)对查询结果进行分组并统计
GET:http://127.0.0.1:9200/shopping/_search -- 对查询结果分组并统计
需要在请求体中传入数据信息:
{
"aggs": { // 表示聚合操作
"price_group": { // 表示对价格进行分组的名称(名字可以随便起)
"terms": { // 分组
"field": "price" // 分组字段
}
}
}
}
响应结果为:
{
"took": 25,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 9,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "1008",
"_score": 1.0,
"_source": {
"title": "华为手机888",
"category": "华为",
"images": "http://www.baidu.com/huawei888.jpg",
"price": 8888.88
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1007",
"_score": 1.0,
"_source": {
"title": "华为手机777",
"category": "华为",
"images": "http://www.baidu.com/huawei777.jpg",
"price": 7777.77
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1006",
"_score": 1.0,
"_source": {
"title": "华为手机666",
"category": "华为",
"images": "http://www.baidu.com/huawei666.jpg",
"price": 6666.66
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1005",
"_score": 1.0,
"_source": {
"title": "华为手机555",
"category": "华为",
"images": "http://www.baidu.com/huawei555.jpg",
"price": 5555.55
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "Ttatkn8BWzMOMKEQR5zC",
"_score": 1.0,
"_source": {
"title": "华为手机",
"category": "华为",
"images": "http://www.baidu.com/huawei.jpg",
"price": 4999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001",
"_score": 1.0,
"_source": {
"title": "华为手机111",
"category": "荣耀",
"images": "http://www.baidu.com/huawei111.jpg",
"price": 1111.11
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1002",
"_score": 1.0,
"_source": {
"title": "华为手机",
"category": "荣耀",
"images": "http://www.baidu.com/huawei.jpg",
"price": 2222.22
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1003",
"_score": 1.0,
"_source": {
"title": "华为手机",
"category": "荣耀",
"images": "http://www.baidu.com/huawei.jpg",
"price": 3333.33
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1004",
"_score": 1.0,
"_source": {
"title": "华为手机444",
"category": "荣耀",
"images": "http://www.baidu.com/huawei444.jpg",
"price": 4444.44
}
}
]
},
"aggregations": {
"price_group": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 1111.1099853515625,
"doc_count": 1
},
{
"key": 2222.219970703125,
"doc_count": 1
},
{
"key": 3333.330078125,
"doc_count": 1
},
{
"key": 4444.43994140625,
"doc_count": 1
},
{
"key": 4999.0,
"doc_count": 1
},
{
"key": 5555.5498046875,
"doc_count": 1
},
{
"key": 6666.66015625,
"doc_count": 1
},
{
"key": 7777.77001953125,
"doc_count": 1
},
{
"key": 8888.8798828125,
"doc_count": 1
}
]
}
}
}
会发现这个操作也会把原始数据返回并显示出来,要想不显示原始数据,需要加一个 size :0
需要在请求体中传入数据信息:
{
"aggs": { // 表示聚合操作
"price_group": { // 表示对价格进行分组的名称(名字可以随便起)
"terms": { // 分组
"field": "price" // 分组字段
}
}
},
"size": 0 // 表示不返回原始数据
}
响应结果为:
{
"took": 10,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 9,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"price_group": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 1111.1099853515625,
"doc_count": 1
},
{
"key": 2222.219970703125,
"doc_count": 1
},
{
"key": 3333.330078125,
"doc_count": 1
},
{
"key": 4444.43994140625,
"doc_count": 1
},
{
"key": 4999.0,
"doc_count": 1
},
{
"key": 5555.5498046875,
"doc_count": 1
},
{
"key": 6666.66015625,
"doc_count": 1
},
{
"key": 7777.77001953125,
"doc_count": 1
},
{
"key": 8888.8798828125,
"doc_count": 1
}
]
}
}
}
2)对查询结果进行分组并求平均值
GET:http://127.0.0.1:9200/shopping/_search -- 对查询结果分组并求平均值
需要在请求体中传入数据信息:
{
"aggs": { // 表示聚合操作
"price_avg": { // 表示对价格进行求平均值的名称(名字可以随便起)
"avg": { // 求平均值
"field": "price" // 分组字段
}
}
},
"size": 0 // 表示不返回原始数据
}
响应结果为:
{
"took": 11,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 9,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"price_avg": {
"value": 4999.884426540799
}
}
}
五、映射关系
① 首先创建一个叫做 user 的索引
PUT :http://127.0.0.1:9200/user → send
② 创建 user 的结构化信息 mapping
PUT:http://127.0.0.1:9200/user/_mapping
请求体参数为:
{
"properties": {
"name": {
"type": "text", // 文本类型,可以分词
"index": true // 表示这个字段可以当做索引去查询
},
"sex": {
"type": "keyword", // 表示这个字段不能分词,必须完全匹配
"index": true // 表示这个字段可以当做索引去查询
},
"tel": {
"type": "text", // 文本类型,可以分词
"index": false // 表示这个字段不可以当做索引去查询
}
}
}
响应结果为:
{
"acknowledged": true
}
③ 添加一条数据:
PUT:http://127.0.0.1:9200/user/_create/1001
请求体参数为:
{
"name": "张三",
"sex": "男的",
"tel": "1111"
}
④ 根据 name 查询数据:
GET:http://127.0.0.1:9200/user/_search
请求体参数为:
{
"query": {
"match": {
"name": "张"
}
}
}
响应结果为:
{
"took": 2418,
"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"
}
}
]
}
}
根据 name ="张" 也能查询出那条数据,说明最开始设置的 name 字段是可以分词的。
⑤ 根据 sex 查询数据:
GET:http://127.0.0.1:9200/user/_search
请求体参数为:
{
"query": {
"match": {
"sex": "男"
}
}
}
响应结果为:
{
"took": 5,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 0,
"relation": "eq"
},
"max_score": null,
"hits": []
}
}
根据 sex ="男" 不能查询出那条数据,说明最开始设置的 sex 字段是不可以分词的,因为它是一个 keyword,需要全匹配,当 sex = "男的",就可以查询出那条数据。
⑥ 根据 tel 查询数据:
GET:http://127.0.0.1:9200/user/_search
请求体参数为:
{
"query": {
"match": {
"tel": "1111"
}
}
}
响应结果为:
{
"error": {
"root_cause": [
{
"type": "query_shard_exception",
"reason": "failed to create query: Cannot search on field [tel] since it is not indexed.",
"index_uuid": "TWNcPxfzSeGMiP7GwBEzew",
"index": "user"
}
],
"type": "search_phase_execution_exception",
"reason": "all shards failed",
"phase": "query",
"grouped": true,
"failed_shards": [
{
"shard": 0,
"index": "user",
"node": "0NL2F-UsRHitMj577IY8rg",
"reason": {
"type": "query_shard_exception",
"reason": "failed to create query: Cannot search on field [tel] since it is not indexed.",
"index_uuid": "TWNcPxfzSeGMiP7GwBEzew",
"index": "user",
"caused_by": {
"type": "illegal_argument_exception",
"reason": "Cannot search on field [tel] since it is not indexed."
}
}
}
]
},
"status": 400
}
根据 tel ="1111" 查询直接报错,错误说明 tel 字段不能用作索引,因为在开始设置的时候就设置的 tel 字段的 index 为 false。