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。