四.全文检索ElasticSearch经典入门-字符串查询&批量查询&DSL查询过滤&乐观锁

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 四.全文检索ElasticSearch经典入门-字符串查询&批量查询&DSL查询过滤&乐观锁

前言

上一章节我们学习的是ElasticSearch的基础操作,在实际的开发中可不只是CURD那么简单,往往伴随着复杂的搜索场景,本篇文章我们将学习如何在ElasticSearch中进行复杂的全文检索。

简单查询

查询所有数据可以使用 GET _search ,查询某个索引库中的所有数据可以使用 GET index/_search

GET orders/_search

携带分页条件

GET orders/_search?size=2&from=2

size是每页条数; from是跳过的条数,和mysql的limit是一样的含义,效果如下:

携带查询参数可以通过 q= ,比如查询count为1的

GET orders/_search?q=count:1&size=10&from=0

需要带排序条件通过 sort=列:desc 指定 desc是倒排,正排是asc ,比如按在价格倒排

GET orders/_search?q=count:1&sort=amount:desc&size=10&from=0

下面是URL中可以携带的参数
在这里插入图片描述
在这里插入图片描述

批量查询

批量查询很重要,对相比单个查询来说,批量查询性能更高。第一种批量查询可以同时查询多个索引库中的文档

GET _mget
{
   
   
    "docs" : [
        {
   
   
            "_index" : "orders",
            "_type" : "_doc",
            "_id" : 1
        },
        {
   
   
            "_index" : "goods",
            "_type" : "_doc",
            "_id" : 1,
            "_source": ["id","title","amount"]
        }
    ]
}

这里的_source 指的是查询的列 ,查询效果如下
在这里插入图片描述
第二种批量获取方式是获取同一个索引库中的多个文档

GET orders/_doc/_mget
{
   
   
    "ids" : [ 1, 2 ]
}

查询效果如下
在这里插入图片描述

版本号控制

ES利用_version 版本号来解决线程并发导致数据丢失问题。需要修改数据时需要指定想要修改文档的version号,如果该版本不是当前版本号,请求将会失败

ElasticSearch中有内部版本号和外部版本号之分。使用内部版本号是要求指定的version字段和当前的version号相同。但在使用外部版本号时要求当前version号小于指定的版本号。如果请求成功,外部版本号作为文档新的version号进行存储。详细参见:连接

外部版本号:

PUT /orders/_doc/2?version=5&version_type=external

内部版本号:

PUT /orders/_doc/1?version=1

新版本使用_seq_no和_primary_term来代替version处理并发问题,比如有如下数据

{
  "_index" : "orders",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 16,
  "_seq_no" : 17,
  "_primary_term" : 3,
  "found" : true,
  "_source" : {
    "id" : 1,
    "title" : "买了1个罗技鼠标",
    "amount" : 200.0,
    "count" : 1,
    "status" : 1
  }
}

修改的时候使用乐观锁控制 ,如果版本号错误,会出现 “version_conflict_engine_exception”错误

PUT orders/_doc/1?if_primary_term=3&if_seq_no=17
{
   
   
  "id":1,
  "title":"买了1个罗技鼠标",
  "amount":200.00,
  "count": 1,
  "status":1
}

DSL查询与DSL过滤

对于简单查询,使用查询字符串比较好,但是对于复杂查询,由于条件多,逻辑嵌套复杂,查询字符串不易组织与表达,且容易出错,因此推荐复杂查询通过DSL使用JSON内容格式的请求体代替。

DSL查询是由ES提供丰富且灵活的查询语言叫做DSL查询(Query DSL),它允许你构建更加复杂、强大的查询。DSL(Domain Specific Language特定领域语言)以JSON请求体的形式出现。DSL主要分为查询DSL(query DSL)和过滤DSL(filter DSL)。

一条查询语句会计算每个文档与查询语句的相关性,会给出一个相关性评分 _score ,并且 按照相关性对匹配到的文档进行,查询语句同时匹配文档,计算相关性,所以更耗时,且不缓存。

一条过滤语句会询问每个文档的字段值是否包含着特定值,它不会去计算任何分值也不关心排序,因此效率会高一点,过滤结果可以缓存并应用到后续请求,过滤语句可有效地配合查询语句完成文档过滤。另外,经常使用过滤器,ES会自动的缓存过滤器的内容,这对于查询来说,会提高很多性能。

看到这里可能还是不太理解DSL查询与DSL过滤的具体区别,我们来举个例子
在这里插入图片描述
我们可以把京东的列表搜索功能分为两部分,第一部分是“关键词”搜索 ; 第二部分是下方的各种条件。那么使用DSL应该怎么做呢?

我们可以把下方的所有条件直接使用DSL过滤来做,因为DSL过滤更像是精品匹配,有或者没有且性能好。对于关键字搜索部分我们通常是放入到 DSL查询部分来做,因为我们通常可以根据关键字进行相关性排序。

一个常用的相对完整的DSL查询

案例:查询索引库orders 中 title包含鼠标的商品,查询第 1 页,每页10条,按照amount 倒排序

GET /orders/_doc/_search
{
   
   
    "query": {
   
   
           "match": {
   
   
             "title":"鼠标"
           }
    },
    "from": 0, 
    "size": 10,
    "_source": ["id", "title", "amount","count"],
    "sort": [{
   
   "amount": "desc"}]
}
  • match : ES的一种查询方式,叫标准匹配,会把搜索的关键字分词后再进行匹配,效果如同: where title = 鼠 or title = 标

DSL查询和DSL综合案例

数据准备,写入两条订单数据

PUT orders/_doc/1
{
   
   
  "id":1,
  "title":"买了1个罗技鼠标",
  "amount":200.00,
  "count": 1,
  "status":1
}
PUT orders/_doc/2
{
   
   
  "id":2,
  "title":"买了2个华为鼠标",
  "amount":100.00,
  "count": 2,
  "status":1
}

案例:查询索引库orders 中 title包含鼠标的商品,amount在 100 到 200 之间 , 状态status为 1的,查询第 2 页,每页10条,按照amount 倒排序

GET /orders/_doc/_search
{
   
   
    "query": {
   
    
        "bool": {
   
   
            "must": [{
   
   
                "match": {
   
   
                    "title": "鼠标"
                }
            }],
            "filter": [{
   
   
                "range":{
   
   
                    "amount":{
   
   
                        "gte":100,
                        "lte":200
                    }
                }
            },
            {
   
   
                "term": {
   
   
                    "status": 1
                }
            }]
        }
    },
    "from": 10,
    "size": 10,
    "sort": [{
   
   
        "amount": "desc"
    }]
}
  • bool :代表的是组合查询,把多种查询方式组合到一起,bool下面包含了must和filter;must和filter里面都可以包含多个查询条件
  • must : bool组合了must和filter , must中的语句是DSL查询,filter中的语句是DSL过滤。must代表其中的条件是必须满足,还可以把must指定为 should 和 must_not;这个位置的语句会进行相关性计算,且按照分数排序,一般会把关键字查询放到这里。

    should下面会带一个以上的条件,至少满足一个条件,这个文档就符合should

    must_not : 文档必须不匹配条件

  • filter : 过滤,里面的查询语句不会处理相关性等,但是会对查询的结果进行缓存,性能好
  • range : 指的是范围 ;get是大于等于 ;let是小于等于
  • term :词元匹配,可以理解为精准匹配,可以用于字符串,数字等类型
  • from : 第2页应该是 (2 - 1 )* 每页条数10

DSL中的查询条件

在上面综合案例中我们用到了4种查询方式:bool ;match ;range ;term ,在ES中还有很多的查询方式来满足我们各种需求

  • 全匹配(match_all):普通搜索(匹配所有文档)

    GET _search
    {
         
         
    "query": {
         
         
      "bool": {
         
         
        "must": [
          {
         
         
            "match_all": {
         
         }
          }
        ],
        "filter": {
         
         
          ...
        }
      }
    }
    }
    
  • 标准查询(match和multi_match)

标准查询,可以理解为,分词查询有点像模糊匹配(like),但又不像,它会对查询的内容进行分词后,得到多个单词,分别带着多个单词去检索ES库,只要有一个单词能查出结果,整个查询就有结果。不管你需要全文本查询还是精确查询基本上都要用到它。

如下面的搜索会对Steven King分词,并找到包含Steven或King的文档,然后给出排序分值。

{
   
   
    "query": {
   
   
        "match": {
   
   
            "fullName": "Steven King"        
        }
    }
}

注意:上面效果如同 where fullName = "Steven" or fullName = "King" ; multi_match 查询允许你做 match查询的基础上同时搜索多个字段:

{
   
   
    "query": {
   
   

        "multi_match": {
   
   

            "query": "Steven King",

            "fields": ["fullName", "title"]

        }
    }
}

上面效果如同:where fileName = Steven or fileName = title or King = fullName or King = title

单词搜索与过滤(Term和Terms)

单词/词元查询 , 可以理解为等值查询,字符串,数字等都可以使用它,把查询的内容看成一个整体去检索ES库

{
   
   
    "query": {
   
   
        "bool": {
   
   
            "must": {
   
   
                "match_all": {
   
   

                }
            },
            "filter": {
   
   
                "term": {
   
   
                    "username": "Steven King"
                }
            }
        }
    }
}

上面效果如同:where username = "Steven King"

提示:上面的“Steven King”会被当成一个词去username中匹配,它跟match不同的地方在于match会把“Steven King”分成“steven”和“king”分别去username中查询。

Terms支持多个字段查询

{
   
   
    "query": {
   
   
        "terms": {
   
   
            "username": [
                "jvm",
                "hadoop",
                "lucene"
            ],
            "minimum_match": 1
        }
    }
}

提示:minimum_match:至少匹配个数,默认为1 ,也就是说username中至少出现三个单词中的一个。

组合条件搜索与过滤(Bool)

组合搜索bool可以组合多个查询条件为一个查询对象,查询条件包括must、should和must_not。

例如:查询爱好有美女,同时也有喜欢游戏或运动,且出生于1990-06-30及之后的人。

{
   
   
    "query": {
   
   
        "bool": {
   
   
            "must": [
                {
   
   
                    "term": {
   
   
                        "hobby": "美女"
                    }
                }
            ],
            "should": [
                {
   
   
                    "term": {
   
   
                        "hobby": "游戏"
                    }
                },
                {
   
   
                    "term": {
   
   
                        "hobby": "运动"
                    }
                }
            ],
            "must_not": [
                {
   
   
                    "range": {
   
   
                        "birth_date": {
   
   
                            "lt": "1990-06-30"
                        }
                    }
                }
            ],
            "filter": [
                ...
            ]
        }
    }
}

上面案例如同:Hobby=美女 and (hobby=游戏 or hobby=运动) and birth_date >= 1990-06-30

提示: 如果 bool 查询下没有must子句,那至少应该有一个should子句。但是 如果有 must子句,那么没有 should子句也可以进行查询。

范围查询与过滤(range)

range过滤允许我们按照指定范围查找一批数据

{
   
   
    "query": {
   
   
        "range": {
   
   
            "age": {
   
   
                "gte": 20,
                "lt": 30
            }
        }
    }
}

上例中查询年龄大于等于20并且小于30。gt:> gte:>= lt:< lte:<=

存在和缺失过滤器(exists和missing)

{
   
   
    "query": {
   
   
        "bool": {
   
   
            "must": [
                {
   
   
                    "match_all": {
   
   

                    }
                }
            ],
            "filter": {
   
   
                "exists": {
   
   
                    "field": "gps"
                }
            }
        }
    }
}

提示:exists和missing只能用于过滤结果。

前匹配搜索与过滤(prefix)

和term查询相似,前匹配搜索不是精确匹配,而是类似于SQL中的like ‘key%’

{
   
   
    "query": {
   
   
        "prefix": {
   
   
            "fullName": "王"
        }
    }
}

提示:上例即查询姓王的所有人。

通配符搜索(wildcard)

使用*代表0~N个,使用?代表1个。

{
   
   
    "query": {
   
   
        "wildcard": {
   
   
            "fullName": "王*锤"
        }
    }
}
相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
16小时前
|
搜索推荐 Java 数据库
springboot集成ElasticSearch的具体操作(系统全文检索)
springboot集成ElasticSearch的具体操作(系统全文检索)
|
15小时前
|
存储 SQL 运维
Elasticsearch 查询革新:探索 Wildcard 类型的高效模糊匹配策略
Elasticsearch 查询革新:探索 Wildcard 类型的高效模糊匹配策略
23 0
|
15小时前
|
运维 测试技术 数据处理
Elasticsearch 优化查询中获取字段内容的方式,性能提升5倍!
Elasticsearch 优化查询中获取字段内容的方式,性能提升5倍!
16 0
|
15小时前
|
存储 缓存 Java
Elasticsearch 8.X 聚合查询下的精度问题及其解决方案
Elasticsearch 8.X 聚合查询下的精度问题及其解决方案
15 0
|
16小时前
|
自然语言处理 Java 索引
SpringBoot 实现 elasticsearch 查询操作(RestHighLevelClient 的案例实战)
SpringBoot 实现 elasticsearch 查询操作(RestHighLevelClient 的案例实战)
24 1
|
16小时前
|
运维 监控 Java
探索Elasticsearch在Java环境下的全文检索应用实践
【4月更文挑战第17天】本文介绍了在Java环境下使用Elasticsearch实现全文检索的步骤。首先,简述了Elasticsearch的功能和安装配置。接着,通过Maven添加`elasticsearch-rest-high-level-client`依赖,创建`RestHighLevelClient`实例连接Elasticsearch。内容包括:创建/删除索引,插入/查询文档。还探讨了高级全文检索功能、性能优化和故障排查技巧。通过Elasticsearch,开发者能高效处理非结构化数据,提升应用程序价值。
|
16小时前
|
存储 关系型数据库 MySQL
ElasticSearch 入门
【2月更文挑战第7天】ElasticSearch 入门 简介 ElasticSearch 的基本概念 ElasticSearch 的查询流程 ElasticSearch 的更新流程
40 2
|
16小时前
|
缓存 算法 索引
【Elasticsearch专栏 07】深入探索:Elasticsearch的倒排索引如何进行模糊查询和通配符查询
Elasticsearch的倒排索引支持模糊查询和通配符查询,通过特定的算法和数据结构,能够实现对关键词的模糊匹配和通配符匹配。这两种查询类型提供了更灵活的搜索功能,但可能影响查询性能,需结合优化策略使用。
|
16小时前
|
存储 自然语言处理 搜索推荐
ElasticSearch入门篇
ElasticSearch入门篇
|
16小时前
|
Java Maven 开发工具
【ElasticSearch 】IK 分词器安装
【ElasticSearch 】IK 分词器安装
23 1

热门文章

最新文章