【Elasticsearch7.0】之搜索简介

  |   0 评论   |   0 浏览

接下来我们来简单了解下,数据的搜索,过滤,聚合等操作。

准备数据

首先创建一份银行账户数据。他的格式为:

{
    "account_number": 0,
    "balance": 16623,
    "firstname": "Bradshaw",
    "lastname": "Mckenzie",
    "age": 29,
    "gender": "F",
    "address": "244 Columbus Place",
    "employer": "Euron",
    "email": "bradshawmckenzie@euron.com",
    "city": "Hobucken",
    "state": "CO"
}

可以通过bulk语法来批量创建数据,数据地址

搜索语法

搜索语法有两种方式,一种是在url里面带上查询条件,另一种是在请求体里面传递查询条件。请求体查询可以使用更加丰富的JSON进行查询。官方建议还用请求体的方式去查询数据。
下面是搜索使用url的示例:

GET /customer/_search?q=*&sort=account_number:asc

这里我们搜索了客户信息,然后q=*表示搜索当前索引下的所有文档。sort=account_number:asc表示对搜索结果按照account_number正序排。pretty表示用漂亮的json格式输出。
部分返回值

{

    "took": 8,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 1000,
            "relation": "eq"
        },
        "max_score": null,
        "hits": [
            {
                "_index": "customer",
                "_type": "_doc",
                "_id": "0",
                "_score": null,
                "_source": {
                    "account_number": 0,
                    "balance": 16623,
                    "firstname": "Bradshaw",
                    "lastname": "Mckenzie",
                    "age": 29,
                    "gender": "F",
                    "address": "244 Columbus Place",
                    "employer": "Euron",
                    "email": "bradshawmckenzie@euron.com",
                    "city": "Hobucken",
                    "state": "CO"
                },
                "sort": [
                    0
                ]
            },
            ...
        ]
    }
}

关于返回值,需要了解下:

  • took:es搜索的时间,单位为毫秒。

  • timed_out:告诉我们搜索是否超时。

  • _shards:告诉我们搜索了多少分片 ,以及成功和失败分片的数量。

  • hits:搜索结果。

  • hits.total:查询结果的总数相关的信息对象。

    • hits.total.value:总共搜索的结果 (需要根据hits.total.relation来解释这个值)。
    • hits.total.relation:如果值为eq,表示刚好等于hits.total.value的值。如果值为gte,表示大于等于hits.total.value的值。
  • hits.hits:实际数组的搜索结果。默认返回10条文档。

  • hits.sort:结果排序的key (如果按score排序,改字段就消失)

  • hits.hits._score:当前文档的得分。

  • hits.max_score:当前结果的最大得分。

可以设置track_total_hits为true,来准确的计数。

上面示例可以用请求体的方式替换为:

GET /customer/_search
{
    "query": {
        "match_all": {}
    },
    "sort": [
        {
            "account_number": "asc"
        }
    ]
}

这里使用json格式的请求体来调用_search接口。
es的搜索直接把结果返回给你了,不会在服务端打开游标。这个跟其他的关系型数据库有所区别。

介绍搜索语法

es提供json格式的查询语法,他被称为:Query DSL。查询语法非常丰富。

"query": { "match_all": {} }

像query,表示这个是一个查询。match_all表示查询的类型。
match_all表示查询所有的文档。
处理query条件外,我们还可以指定其他条件,想sort、size、from等来影响查询结果。

GET /customer/_search
{
"query":{"match_all":{}},
"size":1
}

如果size没有指定,那么默认为10。
from参数:表示从哪个基数开始,默认是0。
size参数:表示取多少文档。
from和size在实现分页的时候非常有用。
sort参数:表示对某些属性进行排序。

深入了解搜索

match_all

默认情况下,查询的结果会所有文档属性都返回,一般用_source来表示。如果你想指定具体某几个属性返回,那么可以在查询中指定。如下:

GET /customer/_search
{
"query":{"match_all":{}},
"_source":["account_number", "balance"]
}

返回值

{
    "took": 92,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 1000,
            "relation": "eq"
        },
        "max_score": 1,
        "hits": [
            {
                "_index": "customer",
                "_type": "_doc",
                "_id": "1",
                "_score": 1,
                "_source": {
                    "account_number": 1,
                    "balance": 39225
                }
            },
            。。。。
        ]
    }
}

可以看出,结果只返回了查询中指定的字段。跟sql中的 select 某字段 from 某表 有点类似。

match

搜索可以对某个字段进行准确搜索。如:

GET /customer/_search
{
    "query": {
        "match": {
            "account_number": 20
        }
    }
}

上面的搜索是查找出account_number=20的数据。

mach_phrase

搜索匹配是否包含查询内容。

GET /customer/_search
{
    "query": {
        "match_phrase": {
            "address": "lane"
        }
    }
}

上面例子搜索出address属性包含lane的数据。

bool query

可以把几个小的查询条件组合成一个大的查询条件。如下例子:

GET /customer/_search
{
	"query":{
		"bool":{
			"must":[
				{"match":{"address":"mill"}},
				{"match":{"address":"lane"}}
			]
		}
	}
}

上面例子会查询出address同时包含mill和lane的数据。
must表示所有条件必须满足,相当于sql中的and。
should表示只要满足其中一个条件就可以,相当于sql中的or。

GET /customer/_search
{
	"query":{
		"bool":{
			"should":[
				{"match":{"address":"mill"}},
				{"match":{"address":"lane"}}
			]
		}
	}
}

示例表示,只要包含mill或者lane其中一个就可以。

must_not表示都不包含。

GET /customer/_search
{
	"query":{
		"bool":{
			"must_not":[
				{"match":{"address":"mill"}},
				{"match":{"address":"lane"}}
			]
		}
	}
}

示例表示既不包含mill,也不包含lane。

当然你可以在bool里面同时使用must、should、must_not。也可以在bool里面在使用bool。

GET /customer/_search
{

    "query": {
        "bool": {
            "must": [
                {
                    "match": {
                        "age": 40
                    }
                }
            ],
            "must_not": [
                {
                    "match": {
                        "state": "ID"
                    }
                }
            ]
        }
    }
}

示例表示返回年龄在40岁且不住在ID的客户。

执行过滤器

之前有看到过_score属性,它表示这个查询结果的得分,得分越高,表示匹配的关联性越高;得分越低,表示匹配的关联性越低。当我们使用filter的时候,得分其实没有必要了。当在使用了filter之后,es会做一些优化,不会去计算这些得分。
像上面的bool查询,就可以使用filter,

GET /customer/_search
{
    "query": {
    	"bool":{
    		"must":{"match_all":{}},
    		"filter":{
    			"range":{
    				"balance":{
    					"gte":20000,
    					"lte":30000
    				}
    			}
    		}
    	}
    }
}

示例使用了范围查询,表示某个字段在一个范围内。这里表示balance>=20000且balance<=30000的客户。
过滤器的性能要高很多,因为他不需要计算得分,所以可以使用过滤器来完成的查询尽量使用过滤器。

聚合

聚合主要是把数据分组或者提取统计信息。你可以简单的理解为就是sql中的group by或者聚合函数。在es中,可以同时返回查询结果和聚合结果。这是非常高效的做法,不然你可能需要执行多次请求,去获取你想要的结果。

GET /customer/_search
{
    "size": 0,
    "aggs": {
        "group_by_state": {
            "terms": {
                "field": "state.keyword"
            }
        }
    }
}

类似这样的sql

SELECT state, COUNT(*) FROM customer GROUP BY state ORDER BY COUNT(*) DESC LIMIT 10;

上面的示例表示不同的洲的客户个数,默认是按降序排。
部分返回值:
image.png
image.png

size表示显示查询结果内容数量。如果你只想看聚合结果,那么可以设置为0。

GET /customer/_search
{
    "size": 0,
    "aggs": {
        "group_by_state": {
            "terms": {
                "field": "state.keyword"
            },
            "aggs": {
                "average_balance": {
                    "avg": {
                        "field": "balance"
                    }
                }
            }
        }
    }
}

示例表示在每个洲的平均账户余额。
部分返回值

{
    。。。
    "aggregations": {
        "group_by_state": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 743,
            "buckets": [
                {
                    "key": "TX",
                    "doc_count": 30,
                    "average_balance": {
                        "value": 26073.3
                    }
                },
                。。。。
            ]
        }
    }
}

可以在聚合里面继续嵌套聚合,这样就可以对聚合结果在进行聚合。我们还可以对聚合结果进行排序。如:

GET /customer/_search
{
    "size": 0,
    "aggs": {
        "group_by_state": {
            "terms": {
                "field": "state.keyword",
                "order":{
                	"average_balance":"desc"
                }
            },
            "aggs": {
                "average_balance": {
                    "avg": {
                        "field": "balance"
                    }
                }
            }
        }
    }
}

示例是对平均余额进行排序。

GET /customer/_search
{
	"size":0,
	"aggs":{
		"group_by_age":{
			"range":{
				"field":"age",
				"ranges":[
					{"from":20,"to":30},
					{"from":30,"to":40},
					{"from":40,"to":50}
				]
			},
			"aggs":{
				"group_by_gender":{
					"terms":{
						"field":"gender.keyword"
					},
					"aggs":{
						"average_balance":{
							"avg":{
								"field":"balance"
							}
						}
					}
				}
			}
		}
	}
}

上面例子演示了我们如何按年龄级别(20-29岁、30-39岁和40-49岁)分组,然后按性别分组,最后得到每个年龄级别、每个性别的平均帐户余额。
返回值

{
    。。。
    "aggregations": {
        "group_by_age": {
            "buckets": [
                {
                    "key": "20.0-30.0",
                    "from": 20,
                    "to": 30,
                    "doc_count": 451,
                    "group_by_gender": {
                        "doc_count_error_upper_bound": 0,
                        "sum_other_doc_count": 0,
                        "buckets": [
                            {
                                "key": "M",
                                "doc_count": 232,
                                "average_balance": {
                                    "value": 27374.05172413793
                                }
                            },
                            {
                                "key": "F",
                                "doc_count": 219,
                                "average_balance": {
                                    "value": 25341.260273972603
                                }
                            }
                        ]
                    }
                },
                {
                    "key": "30.0-40.0",
                    "from": 30,
                    "to": 40,
                    "doc_count": 504,
                    "group_by_gender": {
                        "doc_count_error_upper_bound": 0,
                        "sum_other_doc_count": 0,
                        "buckets": [
                            {
                                "key": "F",
                                "doc_count": 253,
                                "average_balance": {
                                    "value": 25670.869565217392
                                }
                            },
                            {
                                "key": "M",
                                "doc_count": 251,
                                "average_balance": {
                                    "value": 24288.239043824702
                                }
                            }
                        ]
                    }
                },
                。。。
            ]
        }
    }
}

以上是比较简单的聚合方法示例。

也可以关注我的公众号:程序之声
图片
关注公众号,领取更多资源

本文为博主原创文章,未经博主允许不得转载。