ElasticSearch序列 - SpringBoot整合ES:范围查询 range

Posted 我一直在流浪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ElasticSearch序列 - SpringBoot整合ES:范围查询 range相关的知识,希望对你有一定的参考价值。

文章目录

01. ElasticSearch range查询是什么?

Elasticsearch 中的 range 查询可以用于查询某个字段在一定范围内的文档。

range 查询可同时提供包含和不包含这两种范围表达式,可供组合的选项如下:

  • gt: > 大于(greater than)
  • lt: < 小于(less than)
  • gte: >= 大于或等于(greater than or equal to)
  • lte: <= 小于或等于(less than or equal to)

02. ElasticSearch range 查询支持哪些数据类型?

它支持数值、日期、字符串、IP地址、地理范围等类型的字段。

03. ElasticSearch range 查询数值型数据?

① 索引文档,构造数据:

PUT /my_index

  "mappings": 
    "properties": 
      "price":
        "type": "integer"
      
    
  


PUT /my_index/_doc/1

  "price":10


PUT /my_index/_doc/2

  "price":20


PUT /my_index/_doc/3

  "price":30

② 查询 price 字段的值在 10 到 20 之间的文档 :

GET /my_index/_search

  "query": 
    "range": 
      "price": 
        "gte": 10,
        "lte": 20
      
    
  


  "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" : "my_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : 
          "price" : 10
        
      ,
      
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : 
          "price" : 20
        
      
    ]
  

04. ElasticSearch 字符串类型和文本类型的区别?

在Elasticsearch中,字符串类型和文本类型是两种不同的数据类型,它们在索引和搜索时有一些区别。

字符串类型是未经分词的字符串,它们被视为单个词项,并且可以用于精确匹配和范围查询。字符串类型的字段可以映射为keyword类型或text类型。如果将字段映射为keyword类型,则该字段将被视为未经分词的字符串,可以用于精确匹配和范围查询。如果将字段映射为text类型,则该字段将被视为经过分词器处理的文本,可以用于全文搜索和短语匹配。

文本类型是经过分词器处理的文本,它们被拆分成多个词项,并且可以用于全文搜索和短语匹配。文本类型的字段只能映射为text类型。

以下是一些字符串类型和文本类型的区别:

字符串类型可以用于精确匹配和范围查询,而文本类型可以用于全文搜索和短语匹配。
字符串类型的字段可以映射为keyword类型或text类型,而文本类型的字段只能映射为text类型。
字符串类型的字段被视为单个词项,而文本类型的字段被拆分成多个词项。
字符串类型的字段不会被分词器处理,而文本类型的字段会被分词器处理。

总之,字符串类型和文本类型是两种不同的数据类型,它们在索引和搜索时有一些区别。您需要根据具体的需求选择适合的数据类型。

05. ElasticSearch range 查询字符串类型的数据?

在Elasticsearch中,您可以使用range查询来搜索字符串类型的数据,但是在索引时需要注意一些细节。

默认情况下,Elasticsearch会将字符串类型的字段视为text类型,这意味着它们会被分词器处理,并且会被拆分成多个词项。因此,如果您想使用range查询来搜索字符串类型的数据,您需要将字段映射为keyword类型,以便将其视为未经分词的字符串。

① 索引文档,构造数据:

PUT /my_index

  "mappings": 
    "properties": 
      "tag":
        "type": "keyword"
      
    
  


PUT /my_index/_doc/1

  "tag":"A"


PUT /my_index/_doc/2

  "tag":"B"


PUT /my_index/_doc/3

  "tag":"C"

② 查询 tag 字段的值在A到C之间的文档:

GET /my_index/_search

  "query": 
    "range": 
      "tag": 
        "gte": "A",
        "lte": "C"
      
    
  


  "took" : 2,
  "timed_out" : false,
  "_shards" : 
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  ,
  "hits" : 
    "total" : 
      "value" : 3,
      "relation" : "eq"
    ,
    "max_score" : 1.0,
    "hits" : [
      
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : 
          "tag" : "A"
        
      ,
      
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : 
          "tag" : "B"
        
      ,
      
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : 
          "tag" : "C"
        
      
    ]
  

需要注意的是,使用range查询搜索字符串类型的数据时,查询结果是基于字典序的,而不是基于数值大小的。总之,您可以使用range查询来搜索字符串类型的数据,但是在索引时需要将字段映射为keyword类型,以便将其视为未经分词的字符串。

06. ElasticSearch range 无法查询文本类型的数据?

在Elasticsearch中,range查询不适用于文本类型的数据。range查询是基于数值或日期范围的查询,而不是基于文本范围的查询。如果您需要搜索文本类型的数据,可以使用其他类型的查询,例如match查询、prefix查询、wildcard查询、regexp查询等。

07. ElasticSearch range 查询日期类型的数据?

① 索引文档,构造数据:

PUT /my_index

  "mappings": 
    "properties": 
      "createTime":
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss"
      
    
  


PUT /my_index/_doc/1

  "createTime":"2023-03-29 10:30:11"


PUT /my_index/_doc/2

   "createTime":"2023-03-29 10:35:11"


PUT /my_index/_doc/3

   "createTime":"2023-03-29 10:38:11"

② 查询 createTime 字段的值在日期 2023-03-29 10:35:11 到 2023-03-29 10:38:11 之间的文档:

GET /my_index/_search

  "query": 
    "range": 
      "createTime": 
        "gte": "2023-03-29 10:35:11",
        "lte": "2023-03-29 10:38:11"
      
    
  


  "took" : 5,
  "timed_out" : false,
  "_shards" : 
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  ,
  "hits" : 
    "total" : 
      "value" : 2,
      "relation" : "eq"
    ,
    "max_score" : 1.0,
    "hits" : [
      
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : 
          "createTime" : "2023-03-29 10:35:11"
        
      ,
      
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : 
          "createTime" : "2023-03-29 10:38:11"
        
      
    ]
  

08. ElasticSearch range 查询时间戳类型的数据?

① 索引文档,构造数据:

PUT /my_index

  "mappings": 
    "properties": 
      "createTime":
        "type": "date",
        "format": "epoch_millis"
      
    
  


PUT /my_index/_doc/1

  "createTime":1640995200000


PUT /my_index/_doc/2

   "createTime":1672531198000


PUT /my_index/_doc/3

   "createTime":1672531199000

② 查询 createTime 字段的值在时间戳 1640995200000 到 1672531199000之间的文档:


  "took" : 1038,
  "timed_out" : false,
  "_shards" : 
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  ,
  "hits" : 
    "total" : 
      "value" : 3,
      "relation" : "eq"
    ,
    "max_score" : 1.0,
    "hits" : [
      
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : 
          "createTime" : 1640995200000
        
      ,
      
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : 
          "createTime" : 1672531198000
        
      ,
      
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : 
          "createTime" : 1672531199000
        
      
    ]
  

09. ElasticSearch range 查询数组类型数据?

range查询将会匹配包含任何一个数组元素在指定范围内的文档。如果您需要匹配所有数组元素都在指定范围内的文档,可以使用nested查询或parent-child关系来处理嵌套的数组类型数据。

① 索引文档,数据构造:

PUT /my_index

  "mappings": 
    "properties": 
      "price":
        "type": "integer"
      
    
  


PUT /my_index/_doc/1

  "price":[10]


PUT /my_index/_doc/2

  "price":[10,20]


PUT /my_index/_doc/3

  "price":[10,20,30]

② 查询 price 字段的值包含指定范围内(10-20)数值的文档,range查询将会匹配包含任何一个数组元素在指定范围内的文档。


  "took" : 15,
  "timed_out" : false,
  "_shards" : 
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  ,
  "hits" : 
    "total" : 
      "value" : 3,
      "relation" : "eq"
    ,
    "max_score" : 1.0,
    "hits" : [
      
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : 
          "price" : [
            10
          ]
        
      ,
      
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : 
          "price" : [
            10,
            20
          ]
        
      ,
      
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : 
          "price" : [
            10,
            20,
            30
          ]
        
      
    ]
  

10. ElasticSearch range 查询对象类型的数据?

① 索引文档,数据构造:

PUT /my_index

  "mappings": 
    "properties": 
      "person": 
        "type": "object",
        "properties": 
          "name": 
            "type": "keyword"
          ,
          "age": 
            "type": "integer"
          ,
          "address": 
            "type": "keyword"
          
        
      
    
  


PUT /my_index/_doc/1

  "person": 
    "name": "John",
    "age": 30,
    "address": "123 Main St"
  


PUT /my_index/_doc/2

  "person": 
    "name": "Alex",
    "age": 20,
    "address": "123 Main St"
  


PUT /my_index/_doc/3

  "person": 
    "name": "Smith",
    "age": 10,
    "address": "123 Main St"
  

② 查询 person.age 的值字段在10-20之间的文档:

GET /my_index/_search

  "query": 
    "range": 
      "person.age": 
        "gte": 10,
        "lte": 20
      
    
  


  "took" : 1,
  "timed_out" : false,
  "_shards" : 
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  ,
  "hits" : 
    "total" : 
      "value" : 2,
      "relation" : "eq"
    ,
    "max_score" : 1.0,
    "hits" : [
      
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : 
          "person" : 
            "name" : "Alex",
            "age" : 20,
            "address" : "123 Main St"
          
        
      ,

ElasticSearch[v6.2] 在实际项目中的应用

        摘要:本文所讲述的内容,为ElasticSearch(以下简称ES)全文搜索引擎在实际大数据项目的应用;ES的底层是开源库 Lucene。但是,你没法直接用 Lucene,必须自己写代码去调用它的接口。ES 是 Lucene 的封装,java开发,提供了 REST API 的操作接口,开箱即用,是目前全文搜索的首选;

  本文的使用项目为基于Spring Boot 的快速开发环境搭建的项目框架,使用Spring Cloud作为服务治理的框架;集成ES的过程中,考虑过使用Spring Data的方式集成,进行数据的对接,后面通过多方面的调研和学习讨论,最终确定了bboss的集成方案,一个 高性能elasticsearch ORM开发库使用介绍,在这里特别感谢bboss的作者大河和他的团队提供的帮助;

  一、ES基础

网上关于ES的介绍已经特别多,这里将不再进行详细介绍,只是针对几个重点进行说明;

推荐刚开始的小伙伴去看一看阮一峰老师的博客:全文搜索引擎 Elasticsearch 入门教程

  1、Index (索引)--可以理解为关系型数据库中的 数据库的概念

  一个索引就是含有某些相似特性的文档的集合。例如,你可以有一个用户数据的索引,一个产品目录的索引,还有其他的有规则数据的索引。一个索引被一个名称(必须都是小写)唯一标识,并且这个名称被用于索引通过文档去执行索引,搜索,更新和删除操作。

  2、Type(类型)--可以理解为关系型数据库中的 表的概念(6.2版本中一个index下只有一个Type)

  3、Document(文档)--可以理解为关系型数据库中表的ROW

  一个文档是一个可被索引的数据的基础单元。例如,你可以给一个单独的用户创建一个文档,给单个产品创建一个文档,以及其他的单独的规则。这个文档用JSON格式表现,JSON是一种普遍的网络数据交换格式。

  4、Field(字段)--相当于表中的COLUMN

  5、在一个关系型数据库里面,schema定义了表、每个表的字段,还有表和字段之间的关系。 与之对应的,在ES中:Mapping定义索引下的Type的字段处理规则,即索引如何建立、索引类型、是否保存原始索引JSON文档、是否压缩原始JSON文档、是否需要分词处理、如何进行分词处理等。 

   6、ELK是什么?

  ELK=elasticsearch+Logstash+kibana 
  elasticsearch:后台分布式存储以及全文检索 
  logstash: 日志加工、“搬运工” 
  kibana:数据可视化展示。 特别是在DSL的学习过程中,相当于数据库的可视化工具,实时交互操作。
  ELK架构为数据分布式存储、可视化查询和日志解析创建了一个功能强大的管理链。 三者相互配合,取长补短,共同完成分布式大数据处理工作。

  二、ES能解决什么样的问题?

  实际项目开发实战中,几乎每个系统都会有一个搜索的功能,当搜索做到一定程度时,维护和扩展起来难度就会慢慢变大,所以很多公司都会把搜索单独独立出一个模块,用ElasticSearch等来实现。近年ElasticSearch发展迅猛,已经超越了其最初的纯搜索引擎的角色,现在已经增加了数据聚合分析(aggregation)和可视化的特性,如果你有数百万的文档需要通过关键词进行定位时,ElasticSearch肯定是最佳选择。当然,如果你的文档是JSON的,你也可以把ElasticSearch当作一种“NoSQL数据库”, 应用ElasticSearch数据聚合分析(aggregation)的特性,针对数据进行多维度的分析。

  而在本文的项目中,舆情监测部分,搜索功能将是该模块的核心功能;包括条件检索,中文分词,全文搜索等功能,而BBOSS对于该部分功能的实现,提供了极大的便利;

  三、ES环境搭建和在项目中的应用

  1、ES集群搭建,关于ES集群的搭建,这里不再单独介绍,推荐的博客特别多。但有一点要注意,就是不同版本的ES对于功能的支持会有一些区别,要注意;

  2、ES的查询语法;项目集成BBOSS后,比较类似Mybatis框架,直接完成DSL语句的编写放入XML,通过对应的DAO方法调用即可,所以ES的查询语法是ES学习的重点,也是ES进阶的重点,不同的需求对于DSL的查询复杂度不一,可以通过ES的中文官方网站进行阅读学习,并在自身搭建的ES集群提供的kibana中进行操作,ES权威中文指南

  3、项目集成bboss

  第一步、maven引入包

<dependency>
    <groupId>com.bbossgroups.plugins</groupId>
    <artifactId>bboss-elasticsearch-rest</artifactId>
    <version>5.0.6.3</version>
</dependency>

  第二步、bboss elasticsearch配置

运行bboss es需要三个配置文件,放到资源目录(resources)的conf目录下即可:

conf/elasticsearch.xml        es客户端配置文件

conf/httpclient.xml             es http连接池配置文件

conf/elasticsearch.properties   es参数配置文件,在上面的两个xml文件中引用,所以我们只需要修改elasticsearch.properties即可。
  第三步、配置ES查询DSL

在resources下创建配置文件estrace/xxx.xml,配置一个query dsl脚本,名称为queryServiceByCondition,我们将在后面的ClientInterface 组件中通过queryServiceByCondition引用这个脚本,定义脚本内容;

加载query dsl文件,并执行查询操作

  @Override
  public String searchInfo(JSONObject jsonObject) {
        Map<String, Object> params = formatParams(jsonObject);
        JSONObject result = new JSONObject();
        //创建加载配置文件的客户端工具,用来检索文档,单实例多线程安全
        ClientInterface clientUtil = ElasticSearchHelper.getConfigRestClientUtil("esmapper/opinion.xml");
        ESDatas<OpinionInfo> esDatas = clientUtil.searchList("act_yq_info_summary/_search",//act_yq_info_summary为索引名称,search为操作的action
                "searchOpinionInfo",//esmapper/opinion.xml中定义的dsl语句
                params, OpinionInfo.class);
        result.put("esDatas", esDatas);
        return JSONObject.toJSONString(result);
    }

关于BBOSS语法的具体学习,可以移步到  高性能elasticsearch ORM开发库使用介绍,或者入QQ群 166471282

  4、提供一个mapping设置和dsl的示例,仅供参考;

PUT /act_yq_info_summary/
{  
   "settings":{  
      "number_of_shards":6,
      "index.refresh_interval": "5s",
      "analysis" : {
          "analyzer" : {
                "ik" : {
                    "tokenizer" : "ik_max_word"
                }
            }
        }
   },
   "mappings":{  
      "articles":{  
         "dynamic_date_formats":[  
            "yyyy-MM-dd HH:mm:ss",
            "yyyyMMdd",
            "yyyy-MM-dd"
         ],
         "dynamic":"false",
         "properties":{  
            "infoUid":{  
               "type":"text"
            },
            "compareId":{  
               "type":"text"
            },
            "plats":{  
               "type":"keyword"
            },
            "keyWords":{  
               "type":"keyword"
            },
            "infoTitle":{  
               "type":"text",
               "store":true,
               "analyzer" : "ik_max_word"
            },
            "infoDetail":{  
               "type":"text",
               "store":true,
               "analyzer" : "ik_max_word"
            },
            "infoUrl":{  
               "type":"text"
            },
            "pubTime":{  
               "type":"date",
               "format":"yyyy-MM-dd HH:mm:ss"
            },
            "platsType":{  
               "type":"keyword"
            },
            "mlEmotion":{  
               "type":"keyword"
            },
            "userEmotion":{  
               "type":"keyword"
            }
         }
      }
   }
}

查询的DSL

GET act_yq_info_summary/_search
{
    "query": {
        "bool": {
            "must": [{
                    "bool": {
                        "should": [{
                                "match": {
                                    "infoDetail": "乔军"
                                }
                            },
                            {
                                "match": {
                                    "infoTitle": "乔军"
                                }
                            }
                        ]
                    }
                },
                {
                    "terms": {
                        "userEmotion": ["pos", "neg", "neu"]
                    }
                }
            ],
            "filter": {
                "bool": {
                    "must": [{
                            "terms": {
                                "plats": ["jingdong", "toutiao_news", "toutiao_ans", "sina_blog", "sina_com", "bd_news", "bd_konws", "bd_tieba", "zhihu_ques", "zhihu_ans"]
                            }
                        },
                        {
                            "range": {
                                "pubTime": {
                                    "gte": "2016-05-01 00:00:00",
                                    "lte": "2018-05-07 23:59:59"
                                }
                            }
                        },
                        {
                            "terms": {
                                "keyWords": ["蓝月亮湖南卫视中秋晚会", "蓝月亮央视中秋晚会", "蓝月亮旋风孝子"]
                            }
                        }
                    ]
                }
            }
        }
    },
    "highlight": {
        "fields": [{
                "infoTitle": {}
            },
            {
                "infoDetail": {}
            }
        ]
    },
    "from": 0,
    "size": 10,
    "sort": [{
            "_score": {
                "order": "desc"
            }
        },
        {
            "pubTime": {
                "order": "desc"
            }
        }
    ]
}

  5、关于分析器,这里还是推荐IK分词吧,IK分词可以设置 ik_smart  或者  ik_max_word,这里不做详解,推荐使用ik_max_word

  写在最后的话,ES是一个非常强大的搜索引擎,要入门不是很难,但是要精通查询,查询优化,最大程度的搜索最想要的结果是有很多优化的余地的,包括评分机制,包括新版本提供的额聚合功能等,只能说,加油学习吧

以上是关于ElasticSearch序列 - SpringBoot整合ES:范围查询 range的主要内容,如果未能解决你的问题,请参考以下文章

无法从 Elasticsearch 序列化 AWSDate

ElasticSearch返回不同的type的序列化

.NET(C#)通过JSON.NET反序列化Elasticsearch返回响应的结果

未反序列化Spring Data Elasticsearch文档

ElasticSearch序列 - SpringBoot整合ES:根据指定的 ids 查询

ElasticSearch序列 - SpringBoot整合ES:范围查询 range