草庐IT

初识ElasticSearch(2) -文档查询之match查询 | 分词器

做猪呢,最重要的是开森啦 2023-04-20 原文

  • 本系列笔记结合HTTP请求(使用postman调用,源文件见GitHub)和ElasticsearchRestTemplate进行调用学习
  • ElasticsearchRestTemplate封装了RestHighLevelClient,有些场景还得用RestHighLevelClient来操作
  • 版本说明:使用的SpringBoot-2.3.5,对应的ElasticSearch-7.6.2;所以还是可以用RestHighLevelClient
  • ElasticSearch-7.15后就弃用了RestHighLevelClient,可见官网文档,之后的版本可以开启客户端兼容来维持正常使用

1. 分词器:

  • 默认ElasticSearch使用的是内置的standard 分词器,该分词器对中文不太友好,这时可以使用第三方的IK分词器
  • IK分词器的安装方式见链接,分词器的相关介绍见链接

2. match查询:

  • 支持filed类型为text、number、date 、 boolean的查询;text类型查询还支持分词器(analyzer),默认使用内置standard 分词器
  • 分词匹配查询共有三种模式,分别是布尔(boolean)、短语(phrase)和短语前缀(phrase_prefix),默认的匹配查询是布尔类型
  • 查询过程:先对查询字符串进行分词,找出于索引库匹配的稳定
2.1. 数据准备 - 创建带分词器的索引映射

【栗子】:创建blog_match索引,指定title映射,并使用ik_max_word分词器

【HTTP请求】:
·
【API请求】:调用索引创建的API即可,只是注意在实体类添加注解参数
·

2.2. 数据准备 - 添加文档

新增一条"title":“ElasticSearch学习教程”;“content”:“星星之火可以燎原的文档数据”

2.3. 数据准备 - 查看文本分词

对"ElasticSearch学习教程"文本进行ik分词器分析,可见分为elasticsearch、“学习”、"教程"三个分词
·

2.4. 查询 - 映射有分词器的字段查询

【栗子】上述title字段是配置了分词器映射的,这里使用title字段进行查询,查询内容为"Spring data es教程"
·
【参数说明】:

  • query - 搜索的字符串
  • operator - 操作符or或and,默认or,具体含义见【栗子分析】
  • minimum_should_match - 最小匹配单元,整型为分词个数匹配、百分比则为百分比匹配,and操作符时不能使用改参数

·

【HTTP请求】:
·
【栗子分析】

  • 像2.3一样对"Spring data es教程"进行同样的分词分析,分为"spring"、“data”、“es”、"教程"4个分词
  • “minimum_should_match”: “1” 意味着只要有一个分词匹配即可,“operator”:“or” 意味着上述4个分词,任意1个和索引库匹配
  • 可见"教程"这个分词是匹配的,所以能查询到"ElasticSearch学习教程"的文档,如果"minimum_should_match": “2”,那么无法匹配成功
    ·
  • 如果"operator":“and”,意味着搜索词分词的搜索词分词要全部包含在文档索引库中
  • 显然"Spring data es"教程是不匹配的,如果搜索"学习教程",即是匹配的
    `

·
【API请求】:MatchQueryBuilder构建Query
·
searchOne方法获取一个查询结果,如果有多个,取第一个;search方法可以返回多个结果

2.4. 查询 - 映射没有分词器的字段查询

【栗子】上述content字段是没有配置分词器映射的,这里使用content字段进行查询,查询内容为"星的颜色"
·
【HTTP】:
·
【栗子分析】:

  • content默认采用内置standard分词器,会将文本逐字分词,即"星星之火可以燎原",分为了8个分词
  • 当搜素"星的颜色",根据standard,分为4个分词,or操作,minimum_should_match为1,所以符合分词"星"匹配
  • 我们也可以显示指定analyzer分词器查询,根据ik分词,“星的颜色"分为"星”、“的”、"颜色"这3个分词
  • 所以or仍然符合分词"星"匹配能搜索到文档,但and操作不符合匹配,所以搜索不到文档

·

【API请求】:MatchQueryBuilder构建Query指定analyzer分词器
·

3. match_phrase查询:

  • 短语匹配:个人理解为临近分词匹配,查询过程和match类似,也支持指定analyzer分词器查询,此外还可以指定slop临近分词总数量

【数据准备】:文档"title":“Spring Data ElasticSearch小白学习教程”
·
【栗子】查询"Spring教程"
·
【栗子分析】:

  • 文档"Spring Data ElasticSearch小白学习教程"由ik分词会分为"spring",“data”,“elasticsearch”,“小白”,“学习”,"教程"这6个分词
  • 如果不指定slop(默认为0),那么是查询不到文档数据的,如果指定slop>=4,即可查询到文档数据,因为间隔了4个分词

·
【HTTP请求】:
·
【栗子】查询"Spring小白教程"
·
【栗子分析】:

  • 文档"Spring Data ElasticSearch小白学习教程"只需间隔3个分词(“data”,“elasticsearch”,“学习”)即可被查询出来

·

【API请求】:
·

  • 此外,如果值为数组,如:“title”: [“Spring Data ElasticSearch”,“小白学习教程”],那么数组间存在position_increment_gap,默认100
  • 如上述数组搜索"Spring小白教程",则slop值起码为103(100+3),才可搜索得到该文档

4. match_phrase_prefix查询:

短语前缀匹配:在match_phrase基础上,将最后一个分词作为前缀去匹配查询

【数据准备】:文档"title":“小白学习教程Euraka"和文档"title”:“小白学习教程ElasticSearch”
·
【栗子】查询"小白教程E"
·
【栗子分析】:

  • 和match_phras一样,根据slop的设置,保证能进行到E的前缀匹配,通过E作为分词前缀,找到符合的文档
  • max_expansions默认是50,指定为2,意味着取符合E前缀的所有文档的前两个;如果查询小白教程El,那么只能查询到1个
  • max_expansions要注意是同一个分片数据的限制,不同分片可以routing指定,参考资料

·
【HTTP请求】:
·
【API请求】:
·

5. match_bool_prefix查询:

短语前缀乱序匹配:在match基础上的前缀匹配,同样将最后一个分词作为前缀去匹配查询

【数据准备】:文档"title":“小白学习教程Euraka"和文档"title”:“小白学习教程ElasticSearch”
·
【栗子】查询"教程小白El"
·
【栗子分析】:

  • 和match一样,可以设置operator、minimum_should_match参数;通match_phrase_prefix一样可以设置max_expansions参数
  • 不像match_phrase_prefix查询要求文档的"教程"在"小白"之前,match_bool_prefix的分词可以乱序
  • 所以同样的两个数据match_bool_prefix不用设置slop,也能查找到文档

·

【HTTP请求】:
·
【API请求】:暂无找到与之匹配的API,应该是使用bool的,这个后面再介绍
·

6. match_all查询所有:

直接索引/_search即可,也可以match_all使用DSL的方式查询所有文档

【HTTP请求】:
·
【API请求】:
·

7. multi_match查询:

 多字段查询:基于match匹配查询,允许对多个字段进行匹配查询,有六种类型查询

  • best_fields: 默认类型,查询与任何字段匹配的文档,但是使用匹配的最佳字段对应的 _score
  • most_fields:查询与任何字段匹配的文档,并将所有匹配字段的 _score 进行合并
  • cross_fields:把要匹配的所有字段当成一个大字段。对搜索词分析成分词列表,对每个分词在这个大字段上搜索,只要查询到,就算匹配上
  • phrase:在每个要匹配的字段上运行 match_phrase 查询,并使用匹配的最佳字段对应的 _score
  • phrase_prefix:在每个要匹配的字段上运行 match_phrase_prefix 查询,并使用匹配的最佳字段对应的 _score
  • bool_prefix:在每个要匹配的字段上运行 match_bool_prefix 查询,并将所有匹配字段的 _score 进行合并

这里主要讨论best_fields、most_fields、cross_fields,其他的只是各字段查询方式不一样

7.1. best_fields类型查询:

更使用于在同一个字段搜索多个词,因为往往多个词在同一个字段比分开在多个字段更有意义

【数据准备】:准备两个文档内容"

“title”: “我爱北京天安门”,
“content”: “早起去广场上看升旗”

“title”: “我爱我家广场”,
“content”: “广场上看升旗”

·
【栗子】多字段查询"天安门广场上看升旗"
·
【HTTP请求】:
·
【栗子分析】:

  • 按理应该blogId=1的更匹配,但best_fields查询时,最佳字段匹配的文档就越靠前
  • 首先对比title,明显content的关联性更强(词短,匹配的分词多)
  • 虽然blogId=1的title有明确的天安门,但很遗憾,best_fields采用关联性强的conten来进行score
  • 明显blogId=2的content关联性更强(词短,匹配分词多),最终blogId=2的靠前

·
【栗子优化-使用tie_breaker】:

  • tie_breaker:使用这个参数,会把非最佳的score也考虑进去,具体规则:最终_score = 最佳匹配的score+非最佳匹配的score*tie_breaker
  • 1.9850065 = 1.7260926 + 0.8630463 * 0.3;score是怎么算出来的咱也不懂,反正最终的sorce就是这么来的,修改文档好像会影响score
  • 可见,加上tie_breaker后就能较精确搜索到符合的文档

·

【API请求】:multiMatchQuery好像API的score不太一样,母鸡啊
·

7.2. most_fields类型查询:

结合多个字段搜索的相关性,最终评分高的靠前

【数据准备】:准备两个文档内容"

“title”: “我在北京天安门广场”,
“content”: “排队看升旗”

“title”: “我在北京天安门”,
“content”: “广场很多人在排队看升旗”

·
【栗子】多字段查询"广场看升旗"
·
【HTTP请求】:
·
【栗子分析】:

  • 按理应该blogId=2的更匹配,但most_fields查询时,会考虑到其他非最佳字段匹配的相关性
  • 首先blogId=2的title是没有相关性的,而blogId=1有分词"广场",所以有相关性
  • 通过match的普通查询同一个搜索词,对于title结果显示blogId=2的score为0;而blogId=1的score为1.318853;
  • 对于content结果显示blogId=2的score=1.6761261;而blogId=1的score为 0.6460791;
  • 所以最终的score,如blogId=1的是1.9649321 = 0.6460791 + 1.318853,最终blogId=1的靠前

·

【API请求】:multiMatchQuery
·

所以most_fields可以相当于best_fields + tie_breaker的效果,当然most_fields也支持tie_breaker参数

7.3. cross_fields类型查询:
  • 类型相同的字段为一组,类似当作一个大字段;如果有类型不同,也就是多组,那么会结合bool-should来分析
  • 对搜索词分析成分词列表,对每个分词在这个大字段上搜索,只要查询到,就算匹配上
  • multi_match是支持operator和minimum_should_match参数的,但对于best_fields和most_fields会有所出入,因为他们是以字段为中心

【数据准备】:准备两个文档内容,其中这两个字段都是Text类型"

“content”: “ElasticSearch By Tony”,
“author”: “Tom”

“content”: “ElasticSearch Use”,
“content”: “Tony”

·
【栗子】多字段查询"ElasticSearch Tony"

·
【HTTP请求】:most_fields并设置and操作符
·
【栗子分析】:most_fields并设置and操作符

  • ElasticSearch Tony两个分词都需要在content或author字段上匹配才能匹配到文档,所以不能搜索到"ElasticSearch Use"的文档

·
【栗子分析】:most_fields并设置and操作符
·
【HTTP请求】:cross_fields并设置and操作符
·
【栗子分析】:cross_fields并设置and操作符

  • 将同类的字段进行组合,此处类似一个大字段"ElasticSearch Use Tony"
  • cross_fields是以词为中心,将"ElasticSearch","Tony"两个分词同时能在上述字段组合中匹配成功,即可搜索到文档

·
【API请求】:multiMatchQuery
·

cross_fields和best_fields,most_fields一个区别就是cross会将同类字段组合再进行分词匹配

7.4. 字段通配符和字段加权提升:

boost 会影响字段匹配的score,从而影响结果

【官网参考资料】:资料一资料二

有关初识ElasticSearch(2) -文档查询之match查询 | 分词器的更多相关文章

  1. ruby - ECONNRESET (Whois::ConnectionError) - 尝试在 Ruby 中查询 Whois 时出错 - 2

    我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.

  2. ruby-on-rails - 在 Rails 和 ActiveRecord 中查询时忽略某些字段 - 2

    我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr

  3. Matlab imread()读到了什么 (浅显 当复习文档了) - 2

    matlab打开matlab,用最简单的imread方法读取一个图像clcclearimg_h=imread('hua.jpg');返回一个数组(矩阵),往往是a*b*cunit8类型解释一下这个三维数组的意思,行数、数和层数,unit8:指数据类型,无符号八位整形,可理解为0~2^8的数三个层数分别代表RGB三个通道图像rgb最常用的是24-位实现方法,即RGB每个通道有256色阶(2^8)。基于这样的24-位RGB模型的色彩空间可以表现256×256×256≈1670万色当imshow传入了一个二维数组,它将以灰度方式绘制;可以把图像拆分为rgb三层,可以以灰度的方式观察它figure(1

  4. sql - 查询忽略时间戳日期的时间范围 - 2

    我正在尝试查询我的Rails数据库(Postgres)中的购买表,我想查询时间范围。例如,我想知道在所有日期的下午2点到3点之间进行了多少次购买。此表中有一个created_at列,但我不知道如何在不搜索特定日期的情况下完成此操作。我试过:Purchases.where("created_atBETWEEN?and?",Time.now-1.hour,Time.now)但这最终只会搜索今天与那些时间的日期。 最佳答案 您需要使用PostgreSQL'sdate_part/extractfunction从created_at中提取小时

  5. ruby-on-rails - solr 清理查询 - 2

    我在Rails上使用带有ruby​​的solr。一切正常,我只需要知道是否有任何现有代码来清理用户输入,比如以?开头的查询。或* 最佳答案 我不知道执行此操作的任何代码,但理论上可以通过查看parsingcodeinLucene来完成并搜索thrownewParseException(只有16个匹配!)。在实践中,我认为您最好只捕获代码中的任何solr异常并显示“无效查询”消息或类似信息。编辑:这里有几个“sanitizer”:http://pivotallabs.com/users/zach/blog/articles/937-s

  6. ruby-on-rails - Rails 3 在一个查询中包含多个表 - 2

    我正在为锦标赛开发一个Rails应用程序。我在这个查询中使用了三个模型:classPlayertruehas_and_belongs_to_many:tournamentsclassTournament:destroyclassPlayerMatch"Player",:foreign_key=>"player_one"belongs_to:player_two,:class_name=>"Player",:foreign_key=>"player_two"在tournaments_controller的显示操作中,我调用以下查询:Tournament.where(:id=>params

  7. ruby-on-rails - Sunspot:如何对具有不同值的多个字段进行全文查询? - 2

    我想用sunspot重现以下原始solr查询q=exact_term_text:fooORterm_textv:foo*ORalternate_text:bar*但我无法通过标准的太阳黑子界面理解这是否可能以及如何实现,因为看起来:fulltext方法似乎不接受多个文本/搜索字段参数我不知道将什么参数作为第一个参数传递给fulltext,就好像我通过了"foo"或"bar"结果不匹配如果我传递一个空参数,我得到一个q=*:*范围过滤器(例如with(:term).starting_with('foo*')(顾名思义)作为过滤器查询应用,因此不参与评分。似乎可以手动编写字符串(或者可能使

  8. Ruby 等同于 Sphinx 文档生成器? - 2

    Ruby有一些不错的文档生成器,例如Yard、rDoc,甚至Glyph。问题是Sphinx可以做网站、PDF、epub、LaTex等。它在重组文本中完成所有这些事情。在Ruby世界中有替​​代方案吗?也许是程序的组合?如果我也能使用Markdown就更好了。 最佳答案 自1.0版以来,Sphinx有了“域”的概念,它是从Python和/或C以外的语言标记代码实体(如方法调用、对象、函数等)的方法。有一个rubydomain,所以你可以只使用Sphinx本身。您唯一会缺少的(我认为)是Sphinx使用autodoc从源代码自动创建文档

  9. ruby-on-rails - 在不重新查询数据库的情况下重新排序 Rails 中的事件记录? - 2

    例如,假设我有一个名为Products的模型,并且在ProductsController中,我有以下代码用于product_listView以显示已排序的产品。@products=Product.order(params[:order_by])让我们想象一下,在product_listView中,用户可以使用下拉菜单按价格、评级、重量等进行排序。数据库中的产品不会经常更改。我很难理解的是,每次用户选择新的order_by过滤器时,rails是否必须查询,或者rails是否能够以某种方式缓存事件记录以在服务器端重新排序?有没有一种方法可以编写它,以便在用户排序时rails不会重新查询结果

  10. ruby-on-rails - 带句点(或句号)的 Rails 查询字符串。 - 2

    我目前正在尝试了解RoR。我将两个字符串传递到我的Controller中。一个是随机的十六进制字符串,另一个是电子邮件。该项目用于对数据库进行简单的电子邮件验证。我遇到的问题是当我输入如下内容来测试我的页面时:http://signup.testsite.local/confirm/da2fdbb49cf32c6848b0aba0f80fb78c/bob.villa@gmailcom我在:email的参数散列中得到的全部是'bob'。我在gmail和com之间留下了.,因为那样会导致匹配根本不起作用。我的路由匹配如下:match"confirm/:code/:email"=>"conf

随机推荐