Elasticsearch搜索引擎 3(DSL)
Elasticsearch提供了基于JSON的DSL(Domain Specific Language)语句来定义查询条件,其JavaAPI就是在组织DSL条件。
1.DSL查询
-
叶子查询(Leaf query clauses):在特定的字段里查询特定值,属于简单查询。
-
复合查询(Compound query clauses):以逻辑方式组合多个叶子查询或者更改叶子查询的行为方式。
测试:无条件查询match_all
#DSL查询
GET /items/_search
{
"query":{
"match_all": {}
}
}
我们的数量不止10000,但是查询出来的value只有10000,并且数据只显示10条?
Elasticsearch默认超过10000条只显示10000,并且设置了默认分页的查询页数
2.叶子查询
叶子查询类型有很多,可以在官网查看全部
Query DSL | Elasticsearch Guide [7.12] | Elastic
-
全文检索查询(Full Text Queries):利用分词器对用户输入搜索条件先分词,得到词条,然后再利用倒排索引搜索词条。例如:
-
match:单字段
-
multi_match:多字段
-
-
精确查询(Term-level queries):不对用户输入搜索条件分词,根据字段内容精确值匹配。但只能查找keyword、数值、日期、boolean类型的字段。例如:
-
ids
-
term:精准匹配
-
range:范围匹配
-
全文检索查询
1.match
"query":{
"match": {
"字段名": "搜索条件"
}
}
#叶子查询match
GET /items/_search
{
"query":{
"match": {
"name": "牛奶"
}
}
}
存在一个_score关联度打分,返回结果时按照分值降序排列
2.multi_match
"multi_match": {
"query": "搜索条件",
"fields": ["字段1","字段2"]
}
字段1和字段2是“或”关系,只需要满足一个即可
#叶子查询multi_match
GET /items/_search
{
"query":{
"multi_match": {
"query": "宾格瑞",
"fields": ["name","brand"]
}
}
}
精准匹配
不做分词,只根据输入字段匹配
1.term
"term": {
"字段名": {
"value": "查询条件"
}
}
#精确查询term
GET /items/_search
{
"query":{
"term": {
"brand": {
"value": "宾格瑞"
}
}
}
}
2.range
"range": {
"price": {
"gte/gt": 1000,
"lte/lt": 2000
}
}
查询price 1000-2000
#范围查询查询range
GET /items/_search
{
"query":{
"range": {
"price": {
"gte": 1000,
"lte": 2000
}
}
}
}
3.复合查询
复合查询=多个叶子查询
1.算分函数查询
在使用全文检索查询match中返回结果有_score关联度打分,按照分值降序排列,但是日常浏览器搜索中,搜索出来的前几条往往是广告,说明_score关联度打分可控。
function score 查询中包含四部分内容:
-
原始查询条件:query部分,基于这个条件搜索文档,并且基于原始算法打分,原始算分。
-
过滤条件:filter部分,符合该条件的文档才会重新算分。
-
算分函数:符合filter条件的文档要根据这个函数做运算,得到的函数算分,有四种函数
-
weight:函数结果是常量
-
field_value_factor:以文档中的某个字段值作为函数结果
-
random_score:以随机数作为函数结果
-
script_score:自定义算分函数算法
-
-
运算模式:算分函数的结果、原始查询的相关性算分,两者之间的运算方式,包括:
-
multiply:相乘
-
replace:用function score替换query score
-
其它,例如:sum、avg、max、min
-
GET /hotel/_search
{
"query": {
"function_score": {
"query": { .... }, // 原始查询,可以是任意条件
"functions": [ // 算分函数
{
"filter": { // 条件过滤
"term": {
"字段": "过滤条件"
}
},
"weight": 10 // 算分权重为2
}
],
"boost_mode": "multipy" // 加权模式,求乘积
}
}
}
2.bool查询
利用逻辑运算来组合一个或多个查询子句的组合,bool查询支持的逻辑运算有:
-
must:必须匹配每个子查询,类似“与”
-
should:选择性匹配子查询,类似“或”
-
must_not:必须不匹配,不参与算分,类似“非”
-
filter:必须匹配,不参与算分
与搜索关键字无关的查询尽量采用must_not或filter逻辑运算,避免参与相关性算分。
GET /items/_search
{
"query": {
"bool": {
"must": [
{"match": {"name": "手机"}}
],
"should": [
{"term": {"brand": { "value": "华为" }}},
{"term": {"brand": { "value": "小米" }}}
],
"must_not": [
{"range": {"price": {"gte": 2500}}}
],
"filter": [
{"range": {"price": {"lte": 1000}}}
]
}
}
}
4.排序
GET /indexName/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"排序字段": {
"order": "排序方式asc和desc"
}
}
]
}
5.分页
1.基础分页
elasticsearch中通过修改from
、size
参数来控制要返回的分页结果:
-
from
:从第几个文档开始 -
size
:总共查询几个文档
GET /items/_search
{
"query": {
"match_all": {}
},
"from": 0, // 分页开始的位置,默认为0
"size": 10, // 每页文档数量,默认10
"sort": [
{
"price": {
"order": "desc"
}
}
]
}
2.深度分页
在面对数据量比较大时,ELasticsearch会采取分片存储,将数据分成n份,分配到不同的节点上。利于数据的扩展和存储,但是也会存在问题。
我要查找990-1000的数据,从单体结构上,只需要排序然后找前1000名,就可以获得990-1000的数据,但是采取分片存储后,分片1的990-1000是全部数据的990-1000吗,大概率不是。此时,需要找到所有的分片前1000,然后整合到一起,再排序,这样就可以找到总数据的990-1000。
那如果我要找9990-10000,是不是就要找到每个分片的前10000名数据在整合排序查找。
查询分页深度较大时,汇总数据过多,对内存和CPU会产生非常大的压力,因此elasticsearch会禁止from+ size
超过10000的请求。
解决深度分页方案:
-
search after
:分页时需要排序,原理是从上一次的排序值开始,查询下一页数据。官方推荐使用的方式。 -
scroll
:原理将排序后的文档id形成快照,保存下来,基于快照做分页。官方已经不推荐使用。
6.高亮
在浏览器搜索Elasticsearch,发现所有的Elasticsearch、Elastic样式异于其他内容。
对搜索内容进行分词,对分词字段打上高亮标签<em></em>或<strong></strong>
实现:
GET /{索引库名}/_search
{
"query": {
"match": {
"搜索字段": "搜索关键字"
}
},
"highlight": {
"fields": {
"高亮字段名称": {
"pre_tags": "<em>",
"post_tags": "</em>"
}
}
}
}