Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >看完这篇还不会 Elasticsearch 搜索,那我就哭了!

看完这篇还不会 Elasticsearch 搜索,那我就哭了!

作者头像
武培轩
发布于 2020-03-13 01:22:45
发布于 2020-03-13 01:22:45
84100
代码可运行
举报
文章被收录于专栏:武培轩的专栏武培轩的专栏
运行总次数:0
代码可运行

本文主要介绍 ElasticSearch 搜索相关的知识,首先会介绍下 URI Search 和 Request Body Search,同时也会学习什么是搜索的相关性,如何衡量相关性。

Search API

我们可以把 ES 的 Search API 分为两大类,第一类是 URI Search,用 HTTP GET 的方式在 URL 中使用查询参数已达到查询的目的;另一类为 Request Body Search,可以使用 ES 提供的基于 JSON 格式的格式更加完备的查询语言 Query DSL(Domain Specific Language)

语法

范围

/_search

集群上所有的索引

/jvm/_search

jvm

/jvm,sql/_search

jvm 和 sql

/jvm*/_search

以 jvm 开头的索引

在查询的时候需要通过 _search 来标明这个请求为搜索请求,同时可以指定 index,也可以指定多个 index,也可以使用通配符的方式对 index 进行搜索。

下面来看下 URI Search:

URI Search

GET /users/_search?q=username:wupx

URI Search 使用的是 GET 方式,其中 q 指定查询语句,语法为 Query String Syntax,是 KV 键值对的形式;上面的请求表示对 username 字段进行查询,查询包含 wupx 的所有文档。

URI Search 有很多参数可以指定,除了 q 还有如下参数:

  • df:默认字段,不指定时会对所有字段进行查询
  • sort:根据字段名排序
  • from:返回的索引匹配结果的开始值,默认为 0
  • size:搜索结果返回的条数,默认为 10
  • timeout:超时的时间设置
  • fields:只返回索引中指定的列,多个列中间用逗号分开
  • analyzer:当分析查询字符串的时候使用的分词器
  • analyze_wildcard:通配符或者前缀查询是否被分析,默认为 false
  • explain:在每个返回结果中,将包含评分机制的解释
  • _source:是否包含元数据,同时支持 _source_includes_source_excludes
  • lenient:若设置为 true,字段类型转换失败的时候将被忽略,默认为 false
  • default_operator:默认多个条件的关系,AND 或者 OR,默认为 OR
  • search_type:搜索的类型,可以为 dfs_query_then_fetchquery_then_fetch,默认为 query_then_fetch

在了解了基本的查询参数后,让我们先来看下什么是指定字段查询和什么是泛查询?

比如 GET /movies/_search?q=2012&df=title 这个例子就是指定字段查询,同样 GET /movies/_search?q=title:2012 也可以达到指定字段查询的目的。

再举一个泛查询的例子 GET /movies/_search?q=2012,会对所有字段进行查询。

接下来,看下什么是 Term QueryPhrase Query

比如:Beautiful Mind 等效于 Beautiful OR Mind"Beautiful Mind"等效于 Beautiful AND Mind,另外还要求前后顺序保存一致。

当为 Term Query 的时候,就需要把这两个词用括号括起来,请求为 GET /movies/_search?q=title:(Beautiful Mind),意思就是查询 title 中包括 Beautiful 或者 Mind

当为 Phrase Query 的时候就需要用引号包起来,请求为 GET /movies/_search?q=title:"Beautiful Mind"

另外还支持布尔操作,比如 AND(&&)、OR(||)、NOT(!),需要注意大写,不能小写。

在这里举一个 NOT 的例子:GET /movies/_search?q=title:(Beautiful NOT Mind),这个请求表示查询 title 中必须包括 Beautiful 不能包括 Mind 的文档。

URI Search 还包括一些范围查询数学运算符号,比如指定电影的年份大于 1994:GET /movies/_search?q=year:>=1994

URI Search 还支持通配符查询(查询效率低,占用内存大,不建议使用,特别是放在最前面),还支持正则表达式,以及模糊匹配近似查询

URI Search 好处就是操作简单,只要写个 URI 就可以了,方便测试,但是 URI Search 只包含一部分查询语法,不能覆盖所有 ES 支持的查询语法

因此让我们来看下 Request Body Search:

Request Body Search

在 ES 中一些高阶用法只能在 Request Body 里做,所以我们尽量使用 Request Body Search,它支持 GET 和 POST 方式对索引进行查询,需要指定操作的索引名称,同样也要通过 _search 来标明这个请求为搜索请求,我们可以在请求体中使用 ES 提供的 DSL,下面这个例子就是简单的 Query DSL:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
POST /users/_search
{
    "query": {
        "match_all": {}
    }
}

上面的请求的意思就是把所以的结果都返回。

也可以在 Request Body 中加入 fromsize 参数以达到分页的效果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
POST /movies/_search
{
  "from":10,
  "size":20,
  "query":{
    "match_all": {}
  }
}

默认 from 从 0 开始,返回 10 个结果,获取靠后的翻页成本较高。

如果想对搜索的结果排序也可以在请求体中加上 sort 参数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
POST /movies/_search
{
  "sort":[{"year":"desc"}],
  "query":{
    "match_all": {}
  }
}

最好在“数字型”与“日期型”字段上排序,因为对于多值类型或者分析过的字段排序,系统会选一个值,无法得知该值。

如果 _source 的数据量比较大,有些字段也不需要拿到这个信息,那么就可以对它的 _source 进行过滤,把需要的信息加到 _source 中,比如以下请求就是 _source 中只返回 title

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
POST /movies/_search
{
  "_source":["title"],
  "query":{
    "match_all": {}
  }
}

如果 _source 没有存储,那就只返回匹配的文档的元数据,同时 _source 也支持使用通配符。

接下来介绍下脚本字段,脚本字段可以使用 ES 中的 painless 的脚本去算出一个新的字段结果。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
GET /movies/_search
{
  "script_fields": {
    "new_field": {
      "script": {
        "lang": "painless",
        "source": "doc['year'].value+'_hello'"
      }
    }
  },
  "query": {
    "match_all": {}
  }
}

这个例子中就使用 painless 把电影的年份和 _hello 进行拼接形成一个新的字段 new_field

在上面我们刚介绍了在 URI Search 中的 Term QueryPhrase Query,接下来让我们看下 Request Body 中是怎么做的吧!

在此之前先来插播一条小知识-字段类查询,字段类查询主要包括以下两类:

  • 全文匹配:针对 text 类型的字段进行全文检索,会对查询语句先进行分词处理,如 match,match_phrase 等 query 类型
  • 单词匹配:不会对查询语句做分词处理,直接去匹配字段的倒排索引,如 term,terms,range 等 query 类型

好了,现在我们来接着往下看。

可以在 Request Body 中使用在 query match 的方式把信息填在里面,我们先来看下 Match Query,比如下面这个例子,填入两个单词,默认是 wupx or huxy 的查询条件,如果想查询两者同时出现,可以通过加 "operator": "and" 来实现。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
POST /users/_search
{
  "query": {
    "match": {
      "title": "wupx huxy"
      "operator": "and"
    }
  }
}

我们通过一张图来看下 Match Query 的流程:

首先对查询语句进行分词,分成 wupxhuxy 两个 Term,然后 ES 会拿到 username 的倒排索引,对 wupxhuxy 去进行匹配的算分,比如 wupx 对应的文档是 1 和 2,huxy 对应的文档为 1,然后 ES 会利用算分算法(比如 TF/IDF 和 BM25,BM25 模型 5.x 之后的默认模型)列出文档跟查询的匹配得分,然后 ES 会对 wupx huxy 的文档的得分结果做一个汇总,最终根据得分排序,返回匹配文档。

Request Body 中还支持 Match Phrase 查询,但在 query 条件中的词必须顺序出现的,可以通过 slop 参数控制单词间的间隔,比如加上 "slop" :1,表示中间可以有一个其他的字符。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
POST /movies/_search
{
  "query": {
    "match_phrase": {
      "title":{
        "query": "one love"
        "slop":1
      }
    }
  }
}

了解完 Match Query,让我们再来看下 Term Query:

如果不希望 ES 对输入语句作分词处理的话,可以用 Term Query,将查询语句作为整个单词进行查询,使用方法和 Match 类似,只需要把 match 换为 term 就可以了,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
POST /users/_search
{
  "query": {
    "term": {
        "username":"wupx"
    }
  }
}

Terms Query 顾名思义就是一次可以传入多个单词进行查询,关键词是 terms,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
POST /users/_search
{
  "query": {
    "terms": {
      "username": [
        "wupx",
        "huxy"
      ]
    }
  }
}

另外 DSL 还支持特定的 Query String 的查询,比如指定默认查询的字段名 default_field 就和前面介绍的 df 是一样的,在 query 中也可以使用 AND 来实现一个与的操作。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
POST users/_search
{
  "query": {
    "query_string": {
      "default_field": "username",
      "query": "wupx AND huxy"
    }
  }
}

下面来看下 Simple Query String Query,它其实和 Query String 类似,但是会忽略错误的查询语法,同时只支持部分查询语法,不支持 AND OR NOT,会当作字符串处理,Term 之间默认的关系是 OR,可以指定 default_operator 来实现 AND 或者 OR,支持用 + 替代 AND,用 | 替代 OR,用 - 替代 NOT。

下面这个例子就是查询 username 字段中同时包含 wupx 的请求:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "query": {
    "simple_query_string": {
      "query": "wu px",
      "fields": ["username"],
      "default_operator": "AND"
    }
  }
}

到此为止,我们就对 DSL 做了个简单介绍,更高阶的 DSL 会在以后的文章中进行介绍。

然后,我们来看下请求后返回的结果 Response 长什么样吧!

Response

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.9808292,
    "hits" : [
      {
        "_index" : "users",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.9808292,
        "_source" : {
          "username" : "wupx",
          "age" : "18"
        }
      }
    ]
  }
}

其中 took 表示花费的时间;total 表示符合条件的总文档数;hits 为结果集,默认是前 10 个文档;_index 为索引名;_id 为文档 id;_score 为相关性评分;_source 为文档的原始信息。

搜索的相关性(Relevance)

那么我们平时在搜索的时候,比如输入小米手机,会返回很多结果,从用户角度关心的有:是否找到所有相关的内容,有多少不相关的内容被返回了,比如输入的小米手机的时候不应该返回粮食的小米给用户,同时文档应该按照打分的方式进行排序,也就是搜索结果中的 _score,另外,搜索引擎需要结合业务需求,平衡结果排名。

如何评估相关性?

在信息检索学中对相关性是有指标去评估的,第一个是查准率(Precision),具体含义是尽可能返回较少的无关文档给用户;第二个为查全率(Recall),也就是尽量返回较多的相关文档;第三个为是否能够按照相关度进行排序(Ranking)

下面通过一张图来对查准率和查全率有一个更形象的理解:

其中黄色的三角形代表不相关的内容,绿色的圆代表相关的内容;在搜索结果中,黄色的三角形起名为 False Positive(纳伪,简写 fp),通常称作误报,绿色的圆起名为 True Positive(纳真,简写 tp);在没有被搜索到的范围中,绿色的圆的起名为 False Negatives(去真,简写 fn),也常称作漏报,黄色的三角形起名为 True Negative(去伪,简写 tn)

那么我们可以得到:

  • 查准率等于正确的搜索结果除以全部返回的结果,即 Precision = tp / ( tp + fp )
  • 查全率等于正确的搜索结果除以所有应该返回的结果,即 Recall = tp / ( tp + fn )

在 ES 中提供了许多的查询相关参数来改善搜索的 Precision 和 Recall。

总结

本文主要简单介绍了 ES Search API 的两种形式,学习了 URI Search 的基本方法,还学习了 Term Search 和 Phrase Search 的区别,同时介绍了什么叫搜索相关性,以及如何评估相关性。

参考文献 《Elasticsearch技术解析与实战》 Elastic Stack从入门到实践 Elasticsearch顶尖高手系列 Elasticsearch核心技术与实战 https://www.elastic.co/guide/en/elasticsearch/reference/7.1/search.html

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-03-13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【Elasticsearch】4. Search API
Search API URI Search:在URL中使用查询参数 Request Body Search:使用Elasticsearch提供的,基于json格式的更加完备的Query Domain Speacific Language(DSL) 指定查询的索引 /_search:集群上所有的索引 /index1/_search:index1 /index1,index2/_search:index1和index2 /index/_search:以index开头的索引 URI查询 使用"q",指定查询字符
历久尝新
2020/12/15
6720
【Elasticsearch】4. Search API
ElasticSearch学习笔记
Create支持两种方式,一种是指定文档ID创建文档,另一种是让ES自动生成文档ID
UzJu@菜菜狗
2022/04/25
4540
Elasticsearch 利用API进行搜索
ES 在搜索上对外开放了 Resultful API, 方便各个语言调用,那么他调用有两种方式,一种就是单纯将搜索的参数放到url上,还有就是可以放到Request Body里面,我们来依次看看。
憧憬博客
2020/07/21
7690
Elasticsearch 利用API进行搜索
Elasticsearch从入门到放弃:再聊搜索
在前文中我们曾经聊过搜索文档的方法,Elasticsearch 一般适用于读多写少的场景,因此我们需要更多的关注读操作。
Jackeyzhe
2020/07/14
4530
Elasticsearch从入门到放弃:再聊搜索
Elastic学习之旅 (6) Query DSL
大家好,我是Edison。首先说声抱歉,这个ES学习系列很久没更新了,现在继续吧。
Edison Zhou
2024/04/05
1770
Elastic学习之旅 (6) Query DSL
Search - 一文入门ElasticSearch(节点、分片、CRUD、倒排索引、分词)
ElasticSearch是非常重要的检索工具,利用分词、索引(倒排索引)、分词从众多检索工具中脱颖而出,本章是入门基础学习篇内容。
stark张宇
2023/03/16
4.2K0
Elasticsearch 6.x版本全文检索学习之Search API
  方式一、GET /_search,对es中所有的数据进行查询。   方式二、GET /my_index/_search,针对单个索引的数据进行查询。   方式三、GET /my_index1,my_index2/_search,针对两个索引的数据进行查询。   方式四、GET /my_*/_search,指定索引查询,可以一次查询多个。
别先生
2019/11/03
1.4K0
触类旁通Elasticsearch:搜索
ES的搜索请求执行流程如图1所示。图中索引包含两个分片,每个分片有一个副本分片。在给文档定位和评分后,缺省只会获取排名前10的文档。REST API搜索请求被发送到所连接的节点,该节点根据要查询的索引,将这个请求依次发送到所有的相关分片(主分片或者副本分片)。从所有分片收集到足够的排序和排名信息后,只有包含所需文档的分片被要求返回相关内容。这种搜索路由的行为是可配置的,图1展示的默认行为,称为查询后获取(query_then_fetch)。
用户1148526
2019/05/25
3.3K0
ElasticSearch进阶篇之-Query DSL
ElasticSearch官网:https://www.elastic.co/guide/en/elasticsearch/reference/7.4/getting-started-search.html
用户4919348
2022/04/13
7670
ElasticSearch进阶篇之-Query DSL
Elasticsearch7教程
Elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java语言开发的,并作为Apache许可条款下的开放源码发布,是一种流行的企业级搜索引擎。Elasticsearch用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。官方客户端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和许多其他语言中都是可用的。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr,也是基于Lucene。
Remember_Ray
2021/04/05
4.2K0
Elasticsearch初检索及高级
PUT customer/external/1 :在 customer 索引下的 external 类型下保存 1号数据
乐心湖
2021/01/18
1.1K0
Elasticsearch初检索及高级
【elasticsearch】进阶检索
HTTP客户端工具(POSTMAN),get请求不能携带请求体,我们变为post也是一样的 我们 POST 一个 JSON 风格的查询请求体到 _search API。 需要了解,一旦搜索的结果被返回,Elasticsearch 就完成了这次请求,并且不会维护任何服务端的资源或者结果的 cursor(游标)
周杰伦本人
2022/10/25
5450
【elasticsearch】进阶检索
ElasticSearch 权威指南笔记
使用 DSL(Domain Specific Language)特定领域语言**)**查询
operator开发工程师
2023/11/16
2950
ElasticSearch 权威指南笔记
Elasticsearch(六)——Query
上面的语句意思查询userz字段包含tom的文档,结果按照age升序排列,返回第5-14个文档,如果超过1s没有结束,则超时结束 泛查询 等效于在所在字段去匹配改term
羊羽shine
2019/05/29
8610
ElasticSearch-查询
Elasticsearch提供了基于JSON的DSL(Domain Specific Language)来定义查询。常见的查询类型包括:
yuanshuai
2023/11/17
2830
ElasticSearch-查询
017.Elasticsearch搜索操作入门篇
1. 多种搜索方式 1.1 Query String Search:在请求URL中包括search的参数 # 语法 curl -X GET "ip:port/index_name/type_name/
CoderJed
2020/07/06
1.3K0
学好Elasticsearch系列-Query DSL
DSL是Domain Specific Language的缩写,指的是为特定问题领域设计的计算机语言。这种语言专注于某特定领域的问题解决,因而比通用编程语言更有效率。
BookSea
2023/08/03
3650
学好Elasticsearch系列-Query DSL
一起学Elasticsearch系列-Query DSL
DSL是Domain Specific Language的缩写,指的是为特定问题领域设计的计算机语言。这种语言专注于某特定领域的问题解决,因而比通用编程语言更有效率。
BookSea
2023/11/13
5771
一起学Elasticsearch系列-Query DSL
ES常用知识点整理第一部分
第三列倒排索引包含的信息为(文档ID,单词频次,<单词位置>),比如单词“乔布斯”对应的倒排索引里的第一项(1;1;<1>)意思是,文档1包含了“乔布斯”,并且在这个文档中只出现了1次,位置在第一个。
大忽悠爱学习
2023/02/13
5280
ES常用知识点整理第一部分
深入搜索引擎之 Elasticsearch 必知必会(一):开发视角
两句话了解它是什么 1. 搜索引擎。提供了数据存储、数据处理、数据查询、聚合统计的能力。 2. 创始人说:“不要求你必须是一个数据科学家才能把它用好” 前言 Elasticsearch 是一个很有意思的产品,不同岗位的人,对它的关注维度区别比较大 主要可以分三个层面 开发 基本功能 底层工作原理 数据建模最佳实践 运维 容量规划 性能优化 问题诊断 滚动升级 搜索结果优化 查全率、查准率等指标 搜索与如何解决搜索的相似性问题 具体场景下的调优 对比传统数据库的区别主要在于 传统关系型数据库 事务性 Joi
QQ音乐技术团队
2022/01/06
1.3K0
相关推荐
【Elasticsearch】4. Search API
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验