SpringCloud(十)——ElasticSearch简单了解(二)DSL查询语句及RestClient查询文档

news2024/11/27 3:57:30

文章目录

  • 1. DSL查询文档
    • 1.1 DSL查询分类
    • 1.2 全文检索查询
    • 1.3 精确查询
    • 1.4 地理查询
    • 1.5 查询算分
    • 1.6 布尔查询
    • 1.7 结果排序
    • 1.8 分页查询
    • 1.9 高亮显示
  • 2. RestClient查询文档
    • 2.1 查询全部
    • 2.2 其他查询语句
    • 2.3 排序和分页
    • 2.4 高亮显示

1. DSL查询文档

1.1 DSL查询分类

  • 查询所有:查询出所有数据,一般测试用。例如:match_all
  • 全文检索查询:利用分词器对用户输入内容分词,然后去倒排索引库中匹配。例如:
    • match_query
    • multi_match_query
  • 精确查询:根据精确词条值查找数据,一般是查找keyword、数值、日期、boolean等类型字段。例如:
    • ids
    • range
    • term
  • 地理查询:根据经纬度查询。例如:
    • geo_distance
    • geo_bounding_box
  • 复合查询:复合查询可以将上述各种查询条件组合起来,合并查询条件。例如:
    • bool
    • function_score

下面我们以一个基本的查询语句来举例,比如,我们需要查询索引库 hotel 全部内容,使用的DSL语句如下:

GET /hotel/_search
{
  "query": {
    "match_all": {}
  }
}

1.2 全文检索查询

全文检索常用的有两个查询函数,分别是 match 以及 multi_match

  • match 函数会对用户输入内容分词,然后去倒排索引库检索,语法如下:
    GET /indexName/_search
    {
      "query": {
        "match": {
          "FIELD": "TEXT"
        }
      }
    }
    
    比如搜索 hotel 索引库中的 name 字段,如下:
    GET /hotel/_search
    {
      "query": {
        "match": {
          "name": "酒店"
        }
      }
    }
    
  • multi_match 函数与 match 类似,不过允许查询多个字段,语法如下:
    GET /indexName/_search
    {
      "query": {
        "multi_match": {
          "query": "TEXT",
          "fields": ["FIELD1", " FIELD2"]
        }
      }
    }
    
    比如搜索 hotel 索引库中的 name 字段,如下:
    GET /hotel/_search
    {
      "query": {
        "multi_match": {
          "query": "如家",
          "fields": ["name", " brand"]
        }
      }
    }
    

1.3 精确查询

精确查询的语句函数主要有 term 语句和 range 语句,精确查询必须要查询的内容与字段里面的所有内容完全匹配才行,一般的查询是keyword、数值、日期、boolean等类型字段。

  • term 的语法如下:
    GET /indexName/_search
    {
      "query": {
        "term": {
          "FIELD": {
            "value": "VALUE"
          }
        }
      }
    }
    
  • range 查询的语法如下:
    GET /indexName/_search
    {
      "query": {
        "range": {
          "FIELD": {
            "gte": 10,
            "lte": 20
          }
        }
      }
    }
    
    其中 gt 是大于,lt 是小于,gte 是大于等于,lte 是小于等于。

1.4 地理查询

地理查询主要是根据经纬度来进行查询的,主要使用的函数有 geo_bounding_boxgeo_distance

  • geo_bounding_box 函数的语法如下:
    GET /indexName/_search
    {
      "query": {
        "geo_bounding_box": {
          "FIELD": {
            "top_left": {
              "lat": 31.1,
              "lon": 121.5
            },
            "bottom_right": {
              "lat": 30.9,
              "lon": 121.7
            }
          }
        }
      }
    }
    
    该函数能够将在一个矩阵框中的经纬度全部筛选出来,该矩阵的左上角的点以及右下角的点如上述定义所示,根据这两个点已经就能够定义一个矩形了,。
  • geo_distance 函数的语法如下:
    GET /indexName/_search
    {
      "query": {
        "geo_distance": {
          "distance": "15km",
          "FIELD": "31.21,121.5"
        }
      }
    }
    
    该函数是筛选距离定义经纬度点指定距离内的所有点,这个距离指的是距定义点方圆的距离。

1.5 查询算分

在使用关键词等进行查询的时候,会有一个 _score 属性,这就是每条数据与查询关键词的相关性分数,该分数在ElasticSearch5.0之前是使用的 TF-IDF 算法进行的评分,ElasticSearch5.0之后是使用的 BM25 算法进行评分。
在这里插入图片描述
我们可以使用 function score query,修改文档的相关性算分(query score),根据新得到的算分排序。修改算分的示例语句如下:

GET /hotel/_search
{
  "query": {
    "function_score": {
      "query": { "match": {"all": "外滩"} },
      "functions": [
        {
          "filter": {"term": {"id": "1"}},
          "weight": 10
        }
      ],
      "boost_mode": "multiply"
    }
  }
}

在上面的例句中,

  • query 是正常的查询语句
  • filter 表示过滤条件,符合条件的文档才会被重新算分
  • weight 是指算分函数,算分函数的结果称为 function score ,将来会与原始的 query score 运算,得到新算分,常见的算分函数有:
    • weight:给一个常量值,作为函数结果(function score)
    • field_value_factor:用文档中的某个字段值作为函数结果
    • random_score:随机生成一个值,作为函数结果
    • script_score:自定义计算公式,公式结果作为函数结果
  • boost_mode 定义function score与query score的运算方式,常见的加权方式如下:
    • multiply:两者相乘。默认就是这个
    • replace:用function score 替换 query score
    • 其它:sum、avg、max、min

1.6 布尔查询

布尔查询时一个或多个查询的字句,子查询的组合方式有:

  • must:必须匹配每个子查询,类似“与”
  • should:选择性匹配子查询,类似“或”
  • must_not:必须不匹配,不参与算分,类似“非”
  • filter:必须匹配,不参与算分

示例如下:

GET /hotel/_search
{
  "query": {
    "bool": {
      "must": [
        {"term": {"city": "上海" }}
      ],
      "should": [
        {"term": {"brand": "皇冠假日" }},
        {"term": {"brand": "华美达" }}
      ],
      "must_not": [
        { "range": { "price": { "lte": 500 } }}
      ],
      "filter": [
        { "range": {"score": { "gte": 45 } }}
      ]
    }
  }
}

1.7 结果排序

elasticsearch支持对搜索结果排序,默认是根据相关度算分(_score)来排序。可以排序字段类型有:keyword类型、数值类型、地理坐标类型、日期类型等。

GET /indexName/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "FIELD": "desc"  // 排序字段和排序方式ASC、DESC
    }
  ]
}

以上就是指定字段的排序, ASC 代表升序,DASC 代表降序,如果有多个排序字段,那么按照从上到下的优先级进行排序。

举个例子,如果我们想要按照某一个经纬度的距离进行排序,那么模板如下:

GET /indexName/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "_geo_distance" : {
          "FIELD" : "纬度,经度",
          "order" : "asc",
          "unit" : "km"
      }
    }
  ]
}

1.8 分页查询

ElasticSearch查询时默认只显示10条数据,那如果我们想要看到其他的数据怎么办呢?这就涉及到了分页。ElasticSearch分页的方式有很多种,这里讲一下使用 from, size 参数以及 search after 来进行分页。

  • 使用 from, size 两个参数进行分页。可以在搜索时规定这两个参数的值, from 表示从何处开始进行查看,默认是 0 0 0size 表示每次查询的信息有多少条。比如每也10条数据,我们想要查看第二页的数据,那么就需要设置 from: 10,size:10 ,格式如下:

    GET /hotel/_search
    {
     "query": {
       "match_all": {}
     },
     "from": 990, // 分页开始的位置,默认为0
     "size": 10, // 期望获取的文档总数
     "sort": [
       {"price": "asc"}
     ]
    }
    

    但是,这种方式要求 from+size 不大于 10000 10000 10000 ,且该方式是先查询所有的数据,然后再对数据进行截取,不可避免的,该方式会面临深度分页问题,即我们的ElasticSearch肯定是要有集群的,当我们需要取出前 1000 1000 1000 个结果时,需要整理每个集群中的结果,再重新排序,再选出前 1000 1000 1000 个,但是,如果结果集很大,这对内存以及CPU的消耗就很大。

  • 使用 search after 进行分页。针对深度分页,ElasticSearch提供了 search after 方法,该方法没有查询上限,只限制了单次的 size 不超过 10000 10000 10000search after 方法分页时需要排序,原理是从上一次的排序值开始,查询下一页数据。

    例如,我们查询到了第一页的数据,最后一条数据如下:
    在这里插入图片描述
    我们将最后一条数据的 sort 字段复制到 search_after 中,再规定一个 size 属性,就能够在该条数据之后再显示 size 条数据,语法模板如下:

    GET /hotel/_search
    {
     "query": {
       "match_all": {}
     },
     "search_after": [
        161
      ],
     "size": 10,
     "sort": [
       {"price": "asc"}
     ]
    }
    

1.9 高亮显示

在使用搜索引擎进行搜索时,我们发现我们输入的关键词显示都是用了高亮进行显示,这就是搜索结果的高亮。其实,这种高亮的显示是在搜索结果中将关键字用标签进行标注出来,再到页面中进行CSS的渲染。默认在进行高亮查询时会在高亮字段前后添加 em 标签,如果想添加其他标签可以进行更改,语法模板如下:

GET /hotel/_search
{
  "query": {
    "match": {
      "FIELD": "TEXT"
    }
  },
  "highlight": {
    "fields": { // 指定要高亮的字段,可以添加多个字段
      "FIELD": {
        "pre_tags": "<em>",  // 用来标记高亮字段的前置标签,默认就是em标签,所以可以不写
        "post_tags": "</em>" // 用来标记高亮字段的后置标签
      }
    }
  }
}

这里我们对酒店数据进行查询的例子如下:

GET /hotel/_search
{
  "query": {
    "match": {
      "all": "如家"
    }
  },
  "highlight": {
    "fields": { 
      "name": {
        "require_field_match": "false"
      }
    }
  }
}

在上面的搜索中, all 字段是 name, brand 等字段 copy_to 后的属性,而下面高亮显示的属性是 name 属性,这就导致了查询的属性与高亮显示的属性不一致的情况,这种情况默认是不会进行高亮显示的,需要查询的属性与高亮显示的属性一致才进行高亮显示。但是我们就可以设置 require_field_match 属性为 false 控制高亮显示与查询字段和高亮显示的字段无关。

高亮结果显示如下:
在这里插入图片描述

2. RestClient查询文档

2.1 查询全部

查询全部的代码如下所示,

    @Test
    void testMatchAll() throws IOException {
        //1.准备Request对象
        SearchRequest request = new SearchRequest("hotel");
        //2.准备DSL
        request.source().query(QueryBuilders.matchAllQuery());
        //3.发送请求
        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
        //4.解析响应
        SearchHits searchHits = response.getHits();
        //5.1 获取总条数
        long total = searchHits.getTotalHits().value;
        System.out.println("共有" + total + "条数据");
        //5.2 文档数组存储文档
        SearchHit[] hits = searchHits.getHits();
        for(SearchHit hit: hits){
            //6.获取文档source
            String json = hit.getSourceAsString();
            //7.反序列化
            HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
            System.out.println(hotelDoc);
        }
        System.out.println(response);

    }

其中每一段代码与DSL语句的对应关系如下:
在这里插入图片描述

2.2 其他查询语句

其实其他查询语句与上述查询全部的语句中大部分代码是类似的,唯一变化的是 request.source().query()query 的参数。

  • match
    // 分别是字段名和查询的语句
    request.source().query(QueryBuilders.matchQuery("all", "如家"));
    
  • multi_match
    // 分别是查询词以及查询字段
    request.source().query(QueryBuilders.matchQuery("如家", "name", "brand"));
    
  • term
    // 分别是查询字段以及查询词
    request.source().query(QueryBuilders.termQuery("city", "成都"));
    
  • range
    // 分别是查询词以及查询条件
    request.source().query(QueryBuilders.rangeQuery("price").gte(100).lte(300));
    
  • 布尔查询
    // 构建布尔查询
    BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
    // must语句
    boolQuery.must(QueryBuilders.termQuery("city", "成都"));
    //filter语句
    boolQuery.filter(QueryBuilders.rangeQuery("price").gte(100).lte(300))
    request.source().query(boolQuery);
    

2.3 排序和分页

排序与分页的代码也仅需要在 request.source().query() 上进行修改即可,修改示例如下:

request.source().query(QueryBuilders.termQuery("city", "成都"));
// 排序
request.source().sort("price", SortOrder.ASC);
//分页
request.source().from(0).size(10);

2.4 高亮显示

高亮显示仅需要在查询的内容后面添加一行代码即可,如下:

// 设置高亮显示并关闭查询字段与高亮字段一致
request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));

但是,设置了高亮后输出发现并不是高亮的内容,需要高亮的内容前后没有标签,这是怎么回事呢?

回顾上面可以发现,高亮的内容与 _source 内容是分开的,是重新的一个字段,于是,我们需要用高亮的字段覆盖原来的字段,那么循环里面的代码如下:

for(SearchHit hit: hits){
    //6.获取文档source
    String json = hit.getSourceAsString();
    //7.反序列化
    HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
    //获取高亮结果
    Map<String, HighlightField> highlightFieldMap = hit.getHighlightFields();
    //简洁判断,判断highlightFieldMap是否为空或者size==0
    if(!CollectionUtils.isEmpty(highlightFieldMap)){
        //获取highlight属性中的name属性
        HighlightField highlightField = highlightFieldMap.get("name");
        if(highlightField != null){
            //得到name属性的第一个值的字符串
            String name = highlightField.getFragments()[0].string();
            //覆盖原本的值
            hotelDoc.setName(name);
        }
    }
    System.out.println(hotelDoc);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/952699.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

中央仓库更新失败,IDEA报错repository is non-nexus repo, or does not indexed

某个仓库未被识别为 Nexus 仓库&#xff0c;或者没有被正确地索引。导致引入依赖一直爆红&#xff0c;找不到。只有本地仓库的依赖没报错&#xff0c;因为下载过了&#xff0c;添加新的依赖就需要到远程仓库找就爆红。 解决 去阿里云Maven官网看了一下&#xff0c;发现阿里云…

详解 SpringMVC 中获取请求参数

文章目录 1、通过ServletAPI获取2、通过控制器方法的形参获取请求参数3、[RequestParam ](/RequestParam )4、[RequestHeader ](/RequestHeader )5、[CookieValue ](/CookieValue )6、通过POJO获取请求参数7、解决获取请求参数的乱码问题总结 在Spring MVC中&#xff0c;获取请…

前后端项目部署上线详细笔记

部署 参考文章&#xff1a;如何部署网站&#xff1f;来比比谁的方法多 - 哔哩哔哩大家好&#xff0c;我是鱼皮&#xff0c;不知道朋友们有没有试着部署过自己开发的网站呢&#xff1f;其实部署网站非常简单&#xff0c;而且有非常多的花样。这篇文章就给大家分享几种主流的前端…

自编码器AE全方位探析:构建、训练、推理与多平台部署

本文深入探讨了自编码器&#xff08;AE&#xff09;的核心概念、类型、应用场景及实战演示。通过理论分析和实践结合&#xff0c;我们详细解释了自动编码器的工作原理和数学基础&#xff0c;并通过具体代码示例展示了从模型构建、训练到多平台推理部署的全过程。 关注TechLead&…

软件测试/测试开发丨Python 学习笔记 之 链表

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/26458 链表与数组的区别 复杂度分析 时间复杂度数组链表插入删除O(n)O(1)随机访问O(1)O(n) 其他角度分析 内存连续&#xff0c;利用CPU的机制&#xff0…

上海炒股开户哪个证券公司好?找谁能开低佣金的账户?

在上海炒股开户选择哪家券商都可以&#xff0c;但是要拿到低佣金的账户就有点难度了。上海&#xff0c;简称“沪&#xff0c;是国务院批复确定的中国国际经济、金融、贸易、航运、科技创新中心&#xff01;正是如此&#xff0c;上海地区的券商公司也是非常之多的&#xff0c;这…

centos安装jdk-8u371-linux-x64.tar.gz包

java -version //查看jdk版本 rpm -qa | grep jdk 删除带有"openjdk"字样的jdk 例: rpm -e --nodeps java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64 下载该版本的jdk(jdk-8u371-linux-x64.tar.gz) (https://www.oracle.com/java/technologies/javase/javase8u2…

AI:04-基于机器学习的蘑菇分类

蘑菇是一类广泛分布的真菌,其中许多种类具有重要的食用和药用价值,但也存在着一些有毒蘑菇。因此,准确地区分可食用和有毒的蘑菇对于保障人们的食品安全和健康至关重要。本研究旨在基于机器学习技术开发一种蘑菇分类系统,以实现对蘑菇的自动分类和识别。通过构建合适的数据…

8年经验之谈 —— 如何用 JMeter 编写性能测试脚本?

Apache JMeter 应该是应用最广泛的性能测试工具。怎么用 JMeter 编写性能测试脚本&#xff1f; 1. 编写 HTTP 性能测试脚本 STEP 1. 添加 HTTP 请求 i STEP 2. 了解配置信息 HTTP 请求各项信息说明&#xff08;以 JMeter 5.1 为例&#xff09;。 如下图所示&#xff1a; W…

MindsDB为许多不支持内置机器学习的数据库带来了机器学习功能

选择平台的首要原则是“靠近数据”,让代码靠近数据是保持低延迟的必要条件。 机器学习,特别是深度学习往往会多次遍历所有数据(遍历一次被称为一个epoch)。对于非常大的数据集来说,理想的情况是在存储数据的地方建立模型,这样就不需要大量的数据传输。目前已经有部分数据…

如何基于CEETRON ENVISON快速打造桌面、Web端仿真后处理系统?

数十年来&#xff0c;计算机数字模拟技术在物理、化学、工程等领域取得巨大进展。但实现完整的数字孪生 以模拟现实&#xff0c;仍需应对高维度、高精度建模的挑战以及计算机算力需求指数的增长。那该如何解决 这些更复杂的问题&#xff1f;采用具有高性能算力的云端资源进行…

【单片机】有人 WH-LTE-7S1 4G cat1 模块,HTTPD模式,字符串传输,文件传输。GPRS模块连接服务器教程。

文章目录 1、配置模块为HTTPD模式 POST字符串传输2、配置模块为HTTPD模式 GET请求3、 上一篇文章&#xff1a;https://qq742971636.blog.csdn.net/article/details/132571592 在上一篇文章里&#xff0c;已经通过TCP 长链接进行服务器与Cat1 GPRS 模块进行双向通信。已经能够满…

【Pinia状态管理】Pinia和Vuex的对比;创建Pinia的Store;Pinia核心概念State、Getters、Actions

目录 1_Pinia和Vuex的对比1.1_介绍pinia1.2_Pinia和Vuex的区别 2_创建Pinia的Store2.1_安装使用2.2_Store2.3_定义一个Store 3_Pinia核心概念State3.1_认识和定义State3.2_操作State 4_Pinia核心概念Getters4.1_认识2.2_访问Getters 5_Pinia核心概念Actions5.1_认识5.2_Actions…

Nat. Mach. Intell 2023 | DrugBAN+:域自适应的可解释双线性插值网络改进药物-靶标预测(DTI)

DrugBAN&#xff1a;Interpretable bilinear attention network with domain adaptation improves drug–target prediction 论文&#xff1a;Interpretable bilinear attention network with domain adaptation improves drug–target prediction | Nature Machine Intellige…

Python爬虫基础之正则表达式

目录 一、什么是正则表达式&#xff1f; 二、re.compile()编译函数 三、group()获取匹配结果函数 四、常用匹配规则 4.1匹配单个字符 4.2匹配前字符次数 4.3匹配原生字符串 4.4匹配字符串开头和结尾 4.5分组匹配 五、re.match()开头匹配函数 六、re.search()全文搜索…

MusicBrainz Picard for Mac :音乐文件ID3编辑器

MusicBrainz Picard for Mac是一款macOS平台的音乐文件ID3编辑器&#xff0c;能够帮助我们在Mac电脑上编辑音乐文件的ID3标签信息&#xff0c;包括艺人、专辑等信息&#xff0c;非常快速和简单方便。Picard是下一代MusicBrainz标记应用程序。 这个新的标签概念是面向专辑的&…

Socks5代理 vs. Socks4代理:特点和区别解析

在网络通信中&#xff0c;使用代理服务器可以提供更安全、匿名的连接。其中&#xff0c;Socks5和Socks4是两种常见的代理协议。本文将深入探讨它们之间的特点和区别&#xff0c;帮助您选择适合自己需求的代理类型。 1.特点概述 -Socks5&#xff08;Socket Secure 5&#xff0…

数字孪生+燃气管理,解锁智慧燃气管理新模式

文章来源&#xff1a;网络 关键词&#xff1a;智慧燃气、智慧燃气数字化、数字孪生、智慧燃气平台、设备设施数字化 智慧燃气作为新兴行业应用&#xff0c;是智慧城市必不可少的一部分&#xff0c;而数字孪生是推动智慧燃气数字化、智能化发展的新动能。 01燃气行业现状 1…

vue3-vuex持久化实现

vue3-vuex持久化实现 一、背景描述二、实现思路1.定义数据结构2.存值3.取值4.清空 三、具体代码1.定义插件2.使用插件 四、最终效果 一、背景描述 有时候我们可能需要在vuex中存储一些静态数据&#xff0c;比如一些下拉选项的字典数据。这种数据基本很少会变化&#xff0c;所以…