使用阿里云试用Elasticsearch学习:3.6 处理人类语言——同义词

词干提取是通过简化他们的词根形式来扩大搜索的范围,同义词 通过相关的观念和概念来扩大搜索范围。 也许没有文档匹配查询 “英国女王“ ,但是包含 “英国君主” 的文档可能会被认为是很好的匹配。

用户搜索 “美国” 并且期望找到包含 美利坚合众国 、 美国 、 美洲 、或者 美国各州 的文档。 然而,他们不希望搜索到关于 国事 或者 政府机构 的结果。

这个例子提供了宝贵的经验,它向我们阐述了,区分不同的概念对于人类是多么简单而对于纯粹的机器是多么棘手的事情。通常我们会对语言中的每一个词去尝试提供同义词以确保任何一个文档都是可发现的,以保证不管文档之间有多么微小的关联性都能够被检索出来。

这样做是不对的。就像我们更喜欢不用或少用词根而不是过分使用词根一样,同义词也应该只在必要的时候使用。 这是因为用户可以理解他们的搜索结果受限于他们的搜索词,如果搜索结果看上去几乎是随机时,他们就会变得无法理解(注:大规模使用同义词会导致查询结果趋向于让人觉得是随机的)。

同义词可以用来合并几乎相同含义的词,如 跳 、 跳越 或者 单脚跳行 ,和 小册子 、 传单 或者 资料手册 。 或者,它们可以用来让一个词变得更通用。例如, 鸟 可以作为 猫头鹰 或 鸽子 的通用代名词,还有, 成人 可以被用于 男人 或者 女人 。

同义词似乎是一个简单的概念,但是正确的使用它们却是非常困难的。在这一章,我们会介绍使用同义词的技巧和讨论它的局限性和陷阱。

同义词扩大了一个匹配文件的范围。正如 词干提取 或者 部分匹配 ,同义词的字段不应该被单独使用,而应该与一个针对主字段的查询操作一起使用,这个主字段应该包含纯净格式的原始文本。 在使用同义词时,参阅 多数字段 的解释来维护相关性。

使用同义词

同义词可以取代现有的语汇单元或 通过使用 同义词 语汇单元过滤器,添加到语汇单元流中:

PUT /my_index
{"settings": {"analysis": {"filter": {"my_synonym_filter": {"type": "synonym", "synonyms": [ "british,english","queen,monarch"]}},"analyzer": {"my_synonyms": {"tokenizer": "standard","filter": ["lowercase","my_synonym_filter" ]}}}}
}
  • 首先,我们定义了一个 同义词 类型的语汇单元过滤器。
  • 我们在 同义词格式 中讨论同义词格式。
  • 然后我们创建了一个使用 my_synonym_filter 的自定义分析器。

同义词可以使用 synonym 参数来内嵌指定,或者必须 存在于集群每一个节点上的同义词文件中。 同义词文件路径由 synonyms_path 参数指定,应绝对或相对于 Elasticsearch config 目录。参照 更新停用词(Updating Stopwords) 的技巧,可以用来刷新的同义词列表。

通过 analyze API 来测试我们的分析器,显示如下:

GET /my_index/_analyze
{"text": ["Elizabeth is the English queen"],"analyzer": "my_synonyms","explain": true
}
Pos 1: (elizabeth)
Pos 2: (is)
Pos 3: (the)
Pos 4: (british,english) 
Pos 5: (queen,monarch) 
  • 所有同义词与原始词项占有同一个位置。

这样的一个文件将匹配任何以下的查询: English queen 、British queen 、 English monarch 或 British monarch 。 即使是一个短语查询也将会工作,因为每个词项的位置已被保存。

在索引和搜索中使用相同的同义词语汇单元过滤器是多余的。 如果在索引的时候,我们用 english 和 british 这两个术语代替 English , 然后在搜索的时候,我们只需要搜索这些词项中的一个。或者,如果在索引的时候我们不使用同义词,然后在搜索的时候,我们将需要把对 English 的查询转换为 english 或者 british 的查询。
是否在搜索或索引的时候做同义词扩展可能是一个困难的选择。我们将探索更多的选择 扩展或收缩。

同义词格式

同义词最简单的表达形式是 逗号分隔:

  • “jump,leap,hop”

如果遇到这些词项中的任何一项,则将其替换为所有列出的同义词。例如:

原始词项:   取代:
────────────────────────────────
jump            → (jump,leap,hop)
leap            → (jump,leap,hop)
hop             → (jump,leap,hop)

或者, 使用 => 语法,可以指定一个词项列表(在左边),和一个或多个替换(右边)的列表:

"u s a,united states,united states of america => usa"
"g b,gb,great britain => britain,england,scotland,wales"
原始词项:   取代:
────────────────────────────────
u s a           → (usa)
united states   → (usa)
great britain   → (britain,england,scotland,wales)

如果多个规则指定同一个同义词,它们将被合并在一起,且顺序无关,否则使用最长匹配。以下面的规则为例:

"united states            => usa",
"united states of america => usa"

如果这些规则相互冲突,Elasticsearch 会将 United States of America 转换为词项 (usa),(of),(america) 。否则,会使用最长的序列,即最终得到词项 (usa) 。

扩展或收缩

在 同义词格式 中,我们看到了可以通过 简单扩展 、 简单收缩 、或_类型扩展_ 来指明同义词规则。 本章节我们将在这三者间做个权衡比较。

本节仅处理单词同义词。多词同义词又增添了一层复杂性,在 多词同义词和短语查询 中,我们将会讨论。

简单扩展

通过 简单扩展 ,我们可以把同义词列表中的任意一个词扩展成同义词列表 所有 的词:

"jump,hop,leap"

扩展可以应用在索引阶段或查询阶段。两者都有优点 (⬆)︎ 和缺点 (⬇)︎。到底要在哪个阶段使用,则取决于性能与灵活性:

索引																										查询索引的大小	⬇︎ 大索引。因为所有的同义词都会被索引,所以索引的大小相对会变大一些。												⬆︎ 正常大小。关联		⬇︎ 所有同义词都有相同的 IDF(至于什么是 IDF ,参见 什么是相关性?),这意味着通用的词和较常用的词都拥有着相同的权重。	⬆︎ 每个同义词 IDF 都和原来一样。性能		⬆︎ 查询只需要找到查询字符串中指定单个词项。																		⬇︎ 对一个词项的查询重写来查找所有的同义词,从而降低性能。灵活性		⬇︎ 同义词规则不能改变现有的文件。对于有影响的新规则,现有的文件都要重建(注:重新索引一次文档)。						⬆︎ 同义词规则可以更新不需要索引文件。

简单收缩

简单收缩 ,把 左边的多个同义词映射到了右边的单个词:

  • “leap,hop => jump”
    它必须同时应用于索引和查询阶段,以确保查询词项映射到索引中存在的同一个值。

相对于简单扩展方法,这种方法也有一些优点和一些缺点:

索引的大小
⬆︎ 索引大小是正常的,因为只有单一词项被索引。
关联
⬇︎ 所有词项的 IDF 是一样的,所以你不能区分比较常用的词、不常用的单词。
性能
⬆︎ 查询只需要在索引中找到单词的出现。
灵活性
⬆︎ 新同义词可以添加到规则的左侧并在查询阶段使用。例如,我们想添加 bound 到先前指定的同义词规则中。那么下面的规则将作用于包含

bound 的查询或包含 bound 的文档索引:

  • “leap,hop,bound => jump”
    似乎对旧有的文档不起作用是么?其实我们可以把上面这个同义词规则改写下,以便对旧有文档同样起作用:
  • “leap,hop,bound => jump,bound”
    当你重建索引文件,你可以恢复到上面的规则(注: leap,hop,bound => jump )来获得查询单个词项的性能优势(注:因为上面那个规则相比这个而言,查询阶段就只要查询一个词了)。

类型扩展

类型扩展是完全不同于简单收缩 或扩张, 并不是平等看待所有的同义词,而是扩大了词的意义,使被拓展的词更为通用。以这些规则为例:

“cat => cat,pet”,
“kitten => kitten,cat,pet”,
“dog => dog,pet”
“puppy => puppy,dog,pet”

通过在索引阶段使用类型扩展:

  • 一个关于 kitten 的查询会发现关于 kittens 的文档。
  • 查询一个 cat 会找到关于 kittens 和 cats 的文档。
  • 一个 pet 的查询将发现有关的 kittens、cats、puppies、dogs 或者 pets 的文档。

或者在查询阶段使用类型扩展, kitten 的查询结果就会被拓展成涉及到 kittens、cats、dogs。

您也可以有两全其美的办法,通过在索引阶段应用类型扩展同义词规则,以确保类型在索引中存在。然后,在查询阶段, 你可以选择不采用同义词(使 kitten 查询只返回 kittens 的文件)或采用同义词, kitten 的查询操作就会返回包括 kittens、cats、pets(也包括 dogs 和 puppies)的相关结果。

前面的示例规则,对 kitten 的 IDF 将是正确的,而 cat 和 pet 的 IDF 将会被 Elasticsearch 降权。然而, 这是对你有利的,当一个针对 kitten 的查询被拓展成了针对 kitten OR cat OR pet 的查询, 那么 kitten 相关的文档就应该排在最上方,其次是 cat 的文件, pet 的文件将被排在最底部。

同义词和分析链

在 同义词格式 一章中,我们使用 u s a 来举例阐述一些同义词相关的知识。那么为什么 我们使用的不是 U.S.A. 呢?原因是, 这个 同义词 的语汇单元过滤器只能接收到在它前面的语汇单元过滤器或者分词器的输出结果(这里看不到原始文本)。

假设我们有一个分析器,它由 standard 分词器、 lowercase 的语汇单元过滤器、 synonym 的语汇单元过滤器组成。文本 U.S.A. 的分析过程,看起来像这样的:

original string(原始文本)                       → "U.S.A."
standard           tokenizer(分词器)            → (U),(S),(A)
lowercase          token filter(语汇单元过滤器)  → (u),(s),(a)
synonym            token filter(语汇单元过滤器)  → (usa)

如果我们有指定的同义词 U.S.A. ,它永远不会匹配任何东西。因为, my_synonym_filter 看到词项的时候,句号已经被移除了,并且字母已经被小写了。

这其实是一个非常需要注意的地方。如果我们想同时使用同义词特性与词根提取特性,那么 jumps 、 jumped 、 jump 、 leaps 、 leaped 和 leap 这些词是否都会被索引成一个 jump ? 我们 可以把同义词过滤器放置在词根提取之前,然后把所有同义词以及词形变化都列举出来:

  • “jumps,jumped,leap,leaps,leaped => jump”

但更简洁的方式将同义词过滤器放置在词根过滤器之后,然后把词根形式的同义词列举出来:

  • “leap => jump”

大小写敏感的同义词

通常,我们把同义词过滤器放置在 lowercase 语汇单元过滤器之后,因此,所有的同义词 都是小写。 但有时会导致奇怪的合并。例如, CAT 扫描和一只 cat 有很大的不同,或者 PET (正电子发射断层扫描)和 pet 。 就此而言,姓 Little 也是不同于形容词 little 的 (尽管当一个句子以它开头时,首字母会被大写)。

如果根据使用情况来区分词义,则需要将同义词过滤器放置在 lowercase 筛选器之前。当然,这意味着同义词规则需要列出所有想匹配的变化(例如, Little、LITTLE、little )。

相反,可以有两个同义词过滤器:一个匹配大小写敏感的同义词,一个匹配大小写不敏感的同义词。例如,大小写敏感的同义词规则可以是这个样子:

"CAT,CAT scan           => cat_scan"
"PET,PET scan           => pet_scan"
"Johnny Little,J Little => johnny_little"
"Johnny Small,J Small   => johnny_small"

大小不敏感的同义词规则可以是这个样子:

"cat                    => cat,pet"
"dog                    => dog,pet"
"cat scan,cat_scan scan => cat_scan"
"pet scan,pet_scan scan => pet_scan"
"little,small"

大小写敏感的同义词规则不仅会处理 CAT scan ,而且有时候也可能会匹配到 CAT scan 中的 CAT (注:从而导致 CAT scan 被转化成了同义词 cat_scan scan )。出于这个原因,在大小写敏感的同义词列表中会有一个针对较坏替换情况的特异规则 cat_scan scan 。

提示: 可以看到它们可以多么轻易地变得复杂。同平时一样, analyze API 是帮手,用它来检查分析器是否正确配置。参阅 测试分析器。

多词同义词和短语查询

至此,同义词看上去还挺简单的。然而不幸的是,复杂的部分才刚刚开始。 为了能使 短语查询 正常工作, Elasticsearch 需要知道每个词在初始文本中的位置。多词同义词会严重破坏词的位置信息,尤其当新增的同义词标记长度各不相同的时候。

我们创建一个同义词语汇单元过滤器,然后使用下面这样的同义词规则:

"usa,united states,u s a,united states of america"
PUT /my_index
{"settings": {"analysis": {"filter": {"my_synonym_filter": {"type": "synonym","synonyms": ["usa,united states,u s a,united states of america"]}},"analyzer": {"my_synonyms": {"tokenizer": "standard","filter": ["lowercase","my_synonym_filter"]}}}}
}GET /my_index/_analyze
{"text": ["The United States is wealthy"],"analyzer": "my_synonyms","explain": true
}

如果你用上面这个同义词语汇单元过滤器索引一个文档,然后执行一个短语查询,那你就会得到惊人的结果,下面这些短语都不会匹配成功:

  • The usa is wealthy
  • The united states of america is wealthy
  • The U.S.A. is wealthy

但是这些短语会:

  • United states is wealthy
  • Usa states of wealthy
  • The U.S. of wealthy
  • U.S. is america

如果你是在查询阶段使同义词,那你就会看到更加诡异的匹配结果。看下这个 validate-query 查询:

查询关键字会被同义词语汇单元过滤器处理成类似这样的信息:

“(usa united u united) (is states s states) (wealthy a of) america”
这会匹配包含有 u is of america 的文档,但是匹配不出任何含有 america 的文档。

使用简单收缩进行短语查询

避免这种混乱的方法是使用 简单收缩, 用单个词项表示所有的同义词, 然后在查询阶段,就只需要针对这单个词进行查询了:

PUT /my_index
{"settings": {"analysis": {"filter": {"my_synonym_filter": {"type": "synonym","synonyms": ["united states,u s a,united states of america=>usa"]}},"analyzer": {"my_synonyms": {"tokenizer": "standard","filter": ["lowercase","my_synonym_filter"]}}}}
}GET /my_index/_analyze
{"text": ["The United States is wealthy"],"analyzer": "my_synonyms","explain": true
}

上面那个查询信息就会被处理成类似下面这样:

Pos 1:  (the)
Pos 2:  (usa)
Pos 3:  (is)
Pos 5:  (wealthy)

现在我们再次执行我们之前做过的那个 validate-query 查询,就会输出一个简单又合理的结果:

“usa is wealthy”
这个方法的缺点是,因为把 united states of america 转换成了同义词 usa, 你就不能使用 united states of america 去搜索出 united 或者 states 。 你需要使用一个额外的字段并用另一个解析器链来达到这个目的。

符号同义词

最后一节内容我们来阐述下怎么对符号进行同义词处理,这和我们前面讲的同义词处理不太一样。 符号同义词 是用别名来表示这个符号,以防止它在分词过程中被误认为是不重要的标点符号而被移除。

虽然绝大多数情况下,符号对于全文搜索而言都无关紧要,但是字符组合而成的表情,或许又会是很有意义的东西,甚至有时候会改变整个句子的含义,对比一下这两句话:

  • 我很高兴能在星期天工作。
  • 我很高兴能在星期天工作 😦 (注:难过的表情)

标准 (注:standard)分词器或许会简单地消除掉第二个句子里的字符表情,致使两个原本意思相去甚远的句子变得相同。

我们可以先使用 映射字符过滤器,在文本被递交给分词器处理之前, 把字符表情替换成符号同义词 emoticon_happy 或者 emoticon_sad :

PUT /my_index
{"settings": {"analysis": {"char_filter": {"emoticons": {"type": "mapping","mappings": [ ":) => emoticon_happy",":( => emoticon_sad"]}},"analyzer": {"my_emoticons": {"char_filter": "emoticons","tokenizer":   "standard","filter":    [ "lowercase" ]]}}}}
}
GET /my-index-000001/_analyze
{"tokenizer": "keyword","char_filter": [ "my_mappings_char_filter" ],"text": "I'm delighted about it :("
}
{"tokens": [{"token": "I'm delighted about it _sad_","start_offset": 0,"end_offset": 25,"type": "word","position": 0}]
}

很少有人会搜 emoticon_happy 这个词,但是确保类似字符表情的这类重要符号被存储到索引中是非常好的做法,在进行情感分析的时候会很有用。当然,我们也可以用真实的词汇来处理符号同义词,比如: happy 或者 sad 。

提示: 映射 字符过滤器是个非常有用的过滤器,它可以用来对一些已有的字词进行替换操作, 你如果想要采用更灵活的正则表达式去替换字词的话,那你可以使用 pattern_replace 字符过滤器。

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

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

相关文章

Leetcode面试经典150_Q14最长公共前缀

题目: 编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""。 思路A:横向/纵向扫描 Python: class Solution:def longestCommonPrefix(self, strs: List[str]) -> str:s "…

微软edge浏览器上网、下载速度慢,如何解决??

🏆本文收录于「Bug调优」专栏,主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&…

【Spring】一问详解什么是Spring IoC和DI

目录 一、IoC & DI入门1.1、Spring1.1.1、什么是容器1.1.2、什么是IoC 1.2、IoC介绍1.2.1、传统程序开发1.2.2、问题分析1.2.3、问题解决1.2.4、 IoC优势 1.3、Bean的作用域1.4、DI介绍 二、IoC详解2.1、Bean的存储2.1.1、类注解的使用2.1.2、获取bean对象的其他方式2.1.3、…

【Linux 命令】内核、驱动调试手段总结

文章目录 1. printk2. strace3. Itrace4. ptrace5. ftrace6. 动态打印7. perf8. devmem9. demsg参考: 1. printk **printk()**是 Linux 内核中最广为人知的函数之一。它是我们打印消息的标准工具,通常也是追踪和调试的最基本方法。 虽然 printk() 是基…

Integer.parseInt

Integer.parseInt 是 Java 中的一个静态方法,用于将字符串参数解析为有符号的十进制整数。这个方法属于 java.lang.Integer 类。 方法签名 java复制代码 public static int parseInt(String s) throws NumberFormatException public static int parseInt(String …

element问题总结之el-table使用fixed中 header换行后固定行错位问题/固定列下陷问题

固定列下陷问题 效果图问题描述解决方案1、为table添加ref2、调用节点重新自适应方法doLayout3、在操作表头的时候触发的函数header-dragend绑定doLayout方法4、成功解决 效果图 问题描述 在使用el-table的fixed中,发现如果header拖拽文本折行的时候会出现下陷 解…

【大数据】大数据概论与Hadoop

目录 1.大数据概述 1.1.大数据的概念 1.2.大数据的应用场景 1.3.大数据的关键技术 1.4.大数据的计算模式 1.5.大数据和云计算的关系 1.6.物联网 2.Hadoop 2.1.核心架构 2.2.版本演进 2.3.生态圈的全量结构 1.大数据概述 1.1.大数据的概念 大数据即字面意思&#x…

SRIO学习(3)使用SRIO IP核进行设计

文章目录 前言一、设计框图二、模块介绍三、上板验证 前言 本文将通过使用SRIO IP核实现数据通信,重点在于打通数据链路,具体的协议内容设计并非重点,打通了链路大家自己根据设计需求来即可。 一、设计框图 看了前面高速接口的一些设计&am…

nandgame中的asm编程Network(网络)

参考:https://zhuanlan.zhihu.com/p/613188641 题目说明: 网络从网络上的另一台计算机接收数据,并在屏幕上显示它。有效载荷将是宽度为 16 像素的图像。有关所使用的网络协议的详细信息,请参阅关卡帮助。网络线被内存映射到地址…

探索算力(云计算、人工智能、边缘计算等):数字时代的引擎

引言 在数字时代,算力是一种至关重要的资源,它是推动科技创新、驱动经济发展的关键引擎之一。简而言之,算力即计算能力,是计算机系统在单位时间内完成的计算任务数量或计算复杂度的度量。随着科技的不断发展和应用范围的不断扩大…

【Java基础】运行第一个Java程序

开始时间: April 8, 2024 结束时间: April 8, 2024 阶段: Done 需要掌握: 1、了解 JDK 的作用,注意下 JDK 和 JRE 的区别 2、知道 xxx.java 的程序是如何实现跨平台(JVM) 3、了解命令行中 javac 的作用,忘了具体怎…

流式密集视频字幕

流式密集视频字幕 摘要1 IntroductionRelated Work3 Streaming Dense Video Captioning Streaming Dense Video Captioning 摘要 对于一个密集视频字幕生成模型,预测在视频中时间上定位的字幕,理想情况下应该能够处理长的输入视频,预测丰富、…

C语言 | Leetcoce C语言题解之第18题四数之和

题目: 题解: int comp(const void* a, const void* b) {return *(int*)a - *(int*)b; }int** fourSum(int* nums, int numsSize, int target, int* returnSize, int** returnColumnSizes) {int** quadruplets malloc(sizeof(int*) * 1001);*returnSize…

Wireshark,结合wireshark讲讲,一个请求从发出到收到响应都经过了什么

Wireshark 是一款强大的网络协议分析工具,用于捕获和分析网络数据包。当我们使用 Wireshark 跟踪一个请求从发出到收到响应的过程时,它能够揭示出这个过程中涉及的各个网络层次、协议交互以及数据包的详细内容。以下是一个典型HTTP请求(以GET…

企业版ChatGPT用户激增至60万;百度文心一言推出个性化声音定制功能

🦉 AI新闻 🚀 企业版ChatGPT用户激增至60万 摘要:OpenAI首席运营官Brad Lightcap在接受采访时透露,企业版ChatGPT的注册用户已超60万,相较2024年1月的15万用户,短短三个月内增长了300%。这一版本自2023年…

PHP获取路径或目录或当前文件名

<?php //获取当前文件的绝对路径 echo "__FILE__: > ".__FILE__; echo <br/>; //获取当前文件的名称 echo basename(__FILE__); echo <br/>; //获取当前脚本的目录 echo "__DIR__: > ".__DIR__; echo <br/>…

使用Redisson实现分布式锁解决幂等问题

业务场景 功能&#xff1a;实现创建订单功能&#xff0c;要求是保证接口幂等。 引入pom依赖 <dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.13.2</version> </…

C++11新特性(2) ——动态内存和智能指针从入门到入坑

动态内存与智能指针 动态内存的使用十分容易出现问题&#xff08;内存泄漏/非法内存&#xff09;&#xff0c;而智能指针能更安全、容易的使用动态内存&#xff0c;因为他负责自动释放所指向的对象&#xff0c;并且在出现异常时&#xff0c;也会自动释放。 两种智能指针&#…

《springcloud alibaba》 四 seata安装以及使用

目录 准备调整db配置准备创建数据库 seata配置nacos配置confi.txt下载向nacos推送配置的脚本 启动seata新建项目order-seata项目 订单项目数据库脚本pom.xmlapplication.yml启动类实体类dao类service类controller类feign类mapper类 stock-seata 库存项目数据库脚本pom.xmlappli…

STM32学习和实践笔记(5):时钟树

STM32一共有4个时钟源。外部时钟高低速各一个&#xff0c;内部时钟高低速各一个。 外部高速时钟是&#xff1a;4-16MHZ的HSE OSC。HS表示高速high speed. E表示外部的external。开发板该处安装的8M晶振。 外部低速时钟是&#xff1a;32.768KHz的LSI OSC。LS表示高速low speed…