同义词搜索是如何做到的?

elasticSearch 同义词搜索 **关键概念理解** 搜索引擎在构建索引和对搜索关键词解析时都有语句分析的过程,lucene中称为analysis。analysis这个过程,又包括两个子过程 tokenizer和filter:tokenizer即大家熟知的分词 ,filter这里的意思可以理解为对分好的词做的相应处理。可以理解为filter被analyzer使用。 **es同义词搜索实战** 中文分词插件这里选择ik,es选用1. 阅读详情

前面几个章节我们使用到了 Lucene 的中文分词器 HanLPAnalyzer,它并不是 Lucene 自带的中文分词器。Lucene 确实自带了一些中文分词器,但是效果比较弱,在生产实践中多用第三方中文分词器。分词的效果直接影响到搜索的效果,比如默认的 HanLPAnalyser 对「北京大学」这个短语的处理是当成完整的一个词,搜索「北京」这个词汇就不一定能匹配到包含「北京大学」的文章。对语句的处理还需要过滤掉停用词,除掉诸于「的」、「他」、「是」等这样的辅助型词汇。如果是英文还需要注意消除时态对单词形式的影响,比如「drive」和「driven」、「take」和「taked」等。还有更加高级的领域例如同义词、近音词等处理同样也是分词器需要考虑的范畴。

Lucence 中的分词器包含两个部分,分别是切词器 Tokenizer 和过滤器 TokenFilter。切词器顾名思义负责切,将一个句子切成一连串单词流,切词器输出的单词流是过滤器的输入,它负责去掉无用的词汇比如停用词,过滤器还可以是词汇转换,比如大小写转换,过滤器还可以生成新词汇,比如同义词。抽象类 Tokenizer 和 TokenFilter 都继承自 TokenStream 抽象类,Tokenizer 负责将文本(Reader)转成单词流,TokenFilter 负责将输入单词流转成另一个单词流。

640?wx_fmt=png
图片

有了上图中的流水线构造出的最终的 TokenStream,Lucene 就会将输入的文章灌入其中得到最终的单词流,然后对单词流中的每个单词建立 Key 到 PostingList 的映射以形成倒排索引。这里的单词流串联的是带有 Payload 的单词,每个单词都会有一些附加属性,诸于单词的文本、单词在文档中的偏移量、单词在单词流中的位置等。

而 Lucene 的分词器 Analyzer 就是上述流水线的工厂类,由它负责制造整条流水线。Lucene 内置了很多种不同功用的分词器,每种分词器都会生产出不同的流水线。

下面我们使用 Lucene 提供的标准切词器观察分词效果,标准切词器是一个基于空格的切词器。

var tokenizer = new StandardTokenizer();
tokenizer.setReader(new StringReader("Dog eat apple and died"));
tokenizer.reset();
var termAttr = tokenizer.addAttribute(CharTermAttribute.class);
var offsetAttr = tokenizer.addAttribute(OffsetAttribute.class);
var positionIncrAttr = tokenizer.addAttribute(PositionIncrementAttribute.class);
while(tokenizer.incrementToken()) {
    System.out.printf("%s offset=%d,%d position_incr=%d\n", termAttr.toString(), offsetAttr.startOffset(), offsetAttr.endOffset(), positionIncrAttr.getPositionIncrement());
}

-------------
Dog offset=0,3 position_incr=1
eat offset=4,7 position_incr=1
apple offset=8,13 position_incr=1
and offset=14,17 position_incr=1
died offset=18,22 position_inc=1

incrementToken() 表示往前走一个词,单词位置+1,到了文本末尾它就会返回 false。termAttr、offsetAttr 和 positionIncrAttr 都是当前单词位置上的附加属性,分别是单词的文本、字符偏移量的开始和结束位置和单词的位置间隔(一般都是 1),这三个属性就停在那里「守株待兔、雁过拔毛」,来一个单词,就立即抽取它的属性值。其中 positionIncrement 代表单词的位置间隔,通常连续两个单词之间的间隔都是 1。

640?wx_fmt=png
图片

下面我们再加上过滤器,将停用词过滤掉,同时再加上大小写转换器,将大写字母转成小写字母。从代码形式上过滤器和切词器会通过构造器串联起来形成一条流水线。

var tokenizer = new StandardTokenizer();
tokenizer.setReader(new StringReader("Dog eat apple and died"));
var stopFilter = new StopFilter(tokenizer, StopFilter.makeStopSet("and"));
var lowercaseFilter = new LowerCaseFilter(stopFilter);
lowercaseFilter.reset();

var termAttr = lowercaseFilter.addAttribute(CharTermAttribute.class);
var offsetAttr = lowercaseFilter.addAttribute(OffsetAttribute.class);
var positionIncrAttr = lowercaseFilter.addAttribute(PositionIncrementAttribute.class);

while(lowercaseFilter.incrementToken()) {
    System.out.printf("%s offset=%d,%d position_incr=%d\n", termAttr.toString(), offsetAttr.startOffset(), offsetAttr.endOffset(), positionIncrAttr.getPositionIncrement());
}

-------------
dog offset=0,3 position_incr=1
eat offset=4,7 position_incr=1
apple offset=8,13 position_incr=1
died offset=18,22 position_incr=2

注意和前面的例子输出进行对比,所有的单词 offset 值并没有发生变化,因为它表示的是在原文中的字符偏移量,而 position_incr 却发生了变化,因为它代表的是单词序列的位置。当停用词被过滤后,单词序列发生了变化,相应的位置也会跟着改变。

640?wx_fmt=png
图片

下面我们来编写分词器 Analyzer 将上述切词器、过滤器进行打包封装

var analyzer = new Analyzer(){
    @Override
    protected TokenStreamComponents createComponents(String fieldName) {
        var tokenizer = new StandardTokenizer();
        var stopFilter = new StopFilter(tokenizer, StopFilter.makeStopSet("and"));
        var lowercaseFilter = new LowerCaseFilter(stopFilter);
        return new TokenStreamComponents(tokenizer, lowercaseFilter);
    }
};
var stream = analyzer.tokenStream("title", "dog eat apple and died");
stream.reset();
var termAttr = stream.addAttribute(CharTermAttribute.class);
var offsetAttr = stream.addAttribute(OffsetAttribute.class);
var positionIncrAttr = stream.addAttribute(PositionIncrementAttribute.class);
while(stream.incrementToken()) {
    System.out.printf("%s offset=%d,%d position_incr=%d\n", termAttr.toString(), offsetAttr.startOffset(), offsetAttr.endOffset(), positionIncrAttr.getPositionIncrement());
}

----------
dog offset=0,3 position_incr=1
eat offset=4,7 position_incr=1
apple offset=8,13 position_incr=1
died offset=18,22 position_incr=2

注意到 analyzer 的 createComponents 有一个 fieldName 参数,这意味着分析器支持为不同的字段定制不同的流水线,这里的 Component 含义就是流水线。analyzer 之所以将流水线的制造过程抽象出来就是为了考虑对象的复用,流水线可以很复杂,涉及到非常繁多的对象构建,analyzer 内部会每个线程共用同一条流水线。当单个流水线对象处理一条又一条文本内容时,需要通过 reset() 方法来重置流水线的状态避免前一条文本内容的状态遗留给后面的内容。

同义词过滤器 SynonymGraphFilter

有一个面试常见的题目就是 Lucene 的同义词搜索是如何实现的?它的实现方式就是通过过滤器对单词流进行泛化扩充,将一个单词变成多个单词,再插入到倒排索引中,在查询阶段也对查询关键词进行同义扩展成多个词汇再合并查询。Lucene 提供了同义词过滤器的默认实现 SynonymFilter,如今在新的版本中它已经被 SynonymGraphFilter 替换,提供了更加精准的实现。同停用词过滤器一样,使用它需要用户自己添加一个同义词表。下面的代码给词汇 dog 增加了同义词 puppy 和 pup。

var analyzer = new Analyzer(){
    @Override
    protected TokenStreamComponents createComponents(String fieldName) {
        var tokenizer = new StandardTokenizer();
        var lowercaseFilter = new LowerCaseFilter(tokenizer);
        var builder = new SynonymMap.Builder();
        builder.add(new CharsRef("dog"), new CharsRef("puppy"), true);
        builder.add(new CharsRef("dog"), new CharsRef("pup"), true);
        SynonymMap synonymMap = null;
        try {
            synonymMap = builder.build();
        } catch (IOException ignored) {
        }
        assert synonymMap != null;
        var synonymFilter = new SynonymGraphFilter(lowercaseFilter, synonymMap, true);
        var stopFilter = new StopFilter(synonymFilter, StopFilter.makeStopSet("and"));
        return new TokenStreamComponents(tokenizer, stopFilter);
    }
};
var stream = analyzer.tokenStream("title", "dog eat apple and died");
stream.reset();
var termAttr = stream.addAttribute(CharTermAttribute.class);
var offsetAttr = stream.addAttribute(OffsetAttribute.class);
var positionIncrAttr = stream.addAttribute(PositionIncrementAttribute.class);
while(stream.incrementToken()) {
    System.out.printf("%s offset=%d,%d position_incr=%d\n", termAttr.toString(), offsetAttr.startOffset(), offsetAttr.endOffset(), positionIncrAttr.getPositionIncrement());
}

-----------
puppy offset=0,3 position_incr=1
pup offset=0,3 position_incr=0
dog offset=0,3 position_incr=0
eat offset=4,7 position_incr=1
apple offset=8,13 position_incr=1
died offset=18,22 position_incr=2

从结果中我们能看出几个问题,第一个是 puppy 的长度是 5,但是 offset 还是原词 dog 的 offset,长度是 3。这意味着 TokenStream 中词汇的长度和 offset 不一定会 match。第二个问题是 puppy 和 dog 、pup 是同义词,但是 position_incr 很明显不一样,只有第一个词汇的增量是 1,其它同义词汇都是原地打转。至于为什么 puppy 在单词流中排在第一个位置而不是 dog,这个实际上是不确定的,它也不会对后续的搜索结果产生任何影响。

640?wx_fmt=png
图片

位置对短语查询 PhraseQuery 的影响

在上一节我们介绍了 Lucene 自带的短语查询功能,它有一个重要的参数 slop,代表着短语之间的最大位置间隔。下面我们来看看同义词对短语查询会产生怎样的影响。下面的代码将会用到上面构造的 analyzer 分析器实例,在构建索引和查询阶段都会用到。

var directory = new RAMDirectory();
var config = new IndexWriterConfig(analyzer);
var indexWriter = new IndexWriter(directory, config);

var doc = new Document();
doc.add(new TextField("title", "dog eat apple and died", Field.Store.YES));
indexWriter.addDocument(doc);

doc = new Document();
doc.add(new TextField("title", "puppy eat apple and died", Field.Store.YES));
indexWriter.addDocument(doc);

doc = new Document();
doc.add(new TextField("title", "pup eat apple and died", Field.Store.YES));
indexWriter.addDocument(doc);

indexWriter.close();

var reader = DirectoryReader.open(directory);
var searcher = new IndexSearcher(reader);
var parser = new QueryParser("title", analyzer);
var query = parser.parse("\"dog eat\"~0");
System.out.println(query);
var hits = searcher.search(query, 10).scoreDocs;
for (var hit : hits) {
    doc = searcher.doc(hit.doc);
    System.out.printf("%.2f => %s\n", hit.score, doc.get("title"));
}
reader.close();
directory.close();

------------
title:"(puppy pup dog) eat"
1.51 => dog eat apple and died
0.99 => puppy eat apple and died
0.99 => pup eat apple and died

从代码中可以看到 QueryParser 会将查询短语进行同义扩展变成 OR 表达式(puppy OR pup OR dog),三个文档都被正确的匹配出来了,只不过原词的得分会偏高一些。另外代码中我们使用了 RAMDirectory,这个是用来进行测试的基于内存的虚拟文件目录,使用起来比较方便不需要指定文件路径拿来即用。这个类在 Lucene 的新版本中已经被置为 deprecated,被 MMapDirectory 所取代。MMapDirectory 使用起来和 FSDirectory 差不多,需要指定文件路径。

AI大模型如何处理电商搜索中的同义词 AI大模型如何处理电商搜索中的同义词 关键词:自然语言处理(NLP), 语言模型, 同义词处理, 搜索优化, 推荐系统, 深度学习 1. 背景介绍 在当今互联网时代,电商搜索系统已经成为消费者获取商品信息的主要渠道。用 阅读详情

相关推荐

lucene5.5做同义词分析器

根据lucene最新版本5.5做同义词分析器,熟悉内部分析构造

Lucene中的同义词

Lucene中的同义词 Lucene的TokenFilter中,有SynonymFilter和SynonymGraphFilter两种来处理同义词。 SynonymFilter不能很好的处理多词同义词,已经被弃用,建议使用SynonymGraphFilter SynonymFilter 和 SynonymGraphFilter的比较 假设有如下文本: fast wi fi network is d...

zx的博客 1745

SynonymWord.txt

23万字【超级丰富同义词库】同义词库,可用各个领域,es同义词库,hanlp同义词库 比如: Aa01A01= 人 士 人物 人士 人氏 人选 Aa01A02= 人类 生人 全人类 Aa01A03= 人手 人员 人口 人丁 口 食指 Aa01A04= 劳力 劳动力 工作者 Aa01A05= 匹夫 个人 Ab04B01= 儿童 孩童 稚童 童稚 童子 孩子 孩儿 孩子家 小儿 小人儿 雏儿 幼儿 娃儿 娃娃 娃子 小子 小小子 竖子 孺子 稚子 童蒙 幼 童 孩 小 孺 囡 小朋友 小不点儿 少年儿童 童男童女 报童 少儿 小孩 小孩子 幼童 小娃 文童 伢儿 女孩儿 毛孩子 小家伙 Ab04B02= 妞 妮子 妮儿 丫头 黄毛丫头 阿囡 女孩子 小妞 女童 Ab04B03= 顽童 小淘气 淘气鬼 孩子头 孩子王 淘气包 Ab04B04= 男童 男孩儿 童男

lucene--同义词简单的实现方式

public class CreateIndex2 { private static final String PATH = "E:/Lucene/Index3/"; private static final String CONTENT = "NOKA"; public static void main(String[] args) throws CorruptIndexExc

qiuzhuoxian的专栏 3323

开关电源PCB安规设计避坑指南:从光耦开槽到变压器挡墙,这些细节决定认证成败

本文深入解析开关电源PCB安规设计中的关键细节,包括光耦开槽、变压器挡墙工艺等12个致命要点。通过实际案例和工艺参数表,揭示如何避免认证失败,特别强调爬电距离和电气间隙的精确控制,助力工程师提升产品安全性和认证通过率。

weixin_42548893的博客 205

电子取证之服务器取证思路

服务器取证是一个技术性很强的领域,涉及到多个环节,包括网站重构、网站代码分析、容器分析等。数据库密码的获取通常通过查看配置文件、日志文件、备份等途径,同时可以通过一些绕过技术如禁用身份验证来获取权限。对于不同的数据库,需要根据其特性采取相应的应对方法和命令。

2401_84830066的博客 2491

Lucene实现自定义中文同义词分词器

---------------------------------------------------------- lucene的分词_中文分词介绍 ---------------------------------------------------------- Paoding:庖丁解牛分词器。已经没有更新了 mmseg:使用搜狗的词库 1.导入包(有两个包:1.带dic的,2

Jonney's house 3278

Halcon手眼标定实战:九点标定法从入门到精通(附完整代码)

本文详细介绍了Halcon环境下九点标定法的完整实现流程,从基础概念到实战技巧,帮助开发者快速掌握手眼标定技术。通过精确采集图像坐标与机械坐标,计算仿射变换矩阵,实现相机与机械臂坐标系的精确映射,适用于工业自动化中的平面定位场景。

v4w5x6的博客 411

lucene 关键词完全匹配 和 分词匹配

原文 https://ask.youkuaiyun.com/questions/271535?utm_medium=distribute.pc_relevant_t0.none-task-ask-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant_t0.none-task-ask-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link 默认

a704397849的博客 1894

智能排班考勤系统原型

可实现从业务预测,到工时预估,再到人员分配全流程自动智能排班。可应用于客服行业或工厂的智能排班系统。

gywm15111336483的专栏 996

产品必备技能(十):如何绘制原型图?先要绘制页面流程图+页面原型图!附实操原型图、流程图实例(抖音)

文章目录目标题目实操步骤模板实操【抖音】APP的视频发布功能页面流程绘制页面流程图合格标准绘制页面原型图合格标准 目标 新入行的产品经理都对原型抱有向往的心境,但是有经验的产品经理不会一上来就画原型,而是先画页面流程再来画原型。通过学习,你将学会如何用页面流程图规划用户行为路径、如何借助原型识别问题、减少风险、有效沟通。 题目 任意选择一款你喜欢的产品,体验某个功能,下载并梳理此功能至少5个以上的页面流程跳转点(后面会解释),还原2 - 3个主要界面的低保真原型图。 实操步骤 可使用手绘以及Process

汪雯琦的博客 4846

lucene原理及java实现_2014-2-13_ lucene (42)源代码解析之SynonymFilter的应用及实现原理...

Lucene42的SynonmFilter使用方法是很简单的;看下面这个demo就可以明白了。package com.xh.lucene;import java.util.Map;import java.util.HashMap;import java.io.StringReader;import java.io.IOException;importorg.apache.lucene.analys...

weixin_31555049的博客 269

华为OD机试真题2026双机位C卷 Python&JS 实现【明日之星选举】

给定一组选票votes。votes[i]代表第 i 张选票的内容,包含一个字符串"zhangsan,hanmei",表示推荐zhangsan为明日之星,反对 hanmei 称为明日之星。赞成或反对使用逗号(,)分割。 给定一个数组n,表示最后将筛选出赞成票最多的n个人,如果赞成票相同,则反对票越少,排序越靠前;如果赞成票和反对票都相同,则按照姓名字典序升序排序。

MISAYAONE的博客 322

Lucene 同义词搜索

Lucene搜索,主要是

IT、游罠的专栏 2358

【MT7628】固件开发-SDK4320添加MT7612E WiFi驱动操作说明

【MT7628】固件开发-SDK4320添加MT7612E WiFi驱动操作说明

wgl307293845的博客 2081

第229篇 轨迹时间参数化——TOPP-RA和速度约束处理

本文介绍了时间最优路径参数化(TOPP)问题及其解法。TOPP研究如何在给定空间路径上分配时间,使机器人运动时间最短且不超速,需满足速度、加速度和力矩约束。经典解法采用相平面法,通过前向和后向扫描确定最优速度曲线。TOPP-RA改进了数值稳定性,支持多约束处理。文章对比了TOPP与轨迹优化的区别,列举了开源工具,并解答了面试常见问题,指出TOPP广泛应用于机械臂、AGV等领域。TOPP不改变路径形状,仅优化速度分配,其最优解具有bang-bang特性。

郑伟强dev的专栏 324

简单记录elasticsearch同义词搜索

在elasticsearch-x.x.x/config新建analysis文件夹,在该文件夹下新建txt文件(其他文件格式也可)若进行中文同义词,TXT文件的编码格式需为UTF-8,否则会报异常"type": "malformed_input_exception","reason": "Input length = 1" PUT /test_indexone { "index": { ...

yzl_66的博客 864

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

搜索引擎算法之同义词、近义词、上位词挖掘

在搜索引擎中,我们会碰到大量的同义词需求。用户在描述同一个东西的时候,会有各种各样的描述。 在电商搜索环境中,同义词分成好几类: 1. 品牌同义词:nokia=诺基亚,Adidas=阿迪达斯 2. 产品同义词:投影仪≈投影机,电话≈cell phone;automobile 和car。 3.旧词和新词:自行车 -> 脚踏车 4...

数据挖掘爱好者 1万+

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Elasticsearch:使用同义词 synonyms 来提高搜索效率

在我们的很多情况下,我们希望在搜索时,有时能够使用一个词的同义词来进行搜索,这样我们能搜索出来更多相关的内容。我们可以通过 text analysis 来帮助我们形成同义词。如果大家对 Elastic 的 analyzer 还不是很熟的话,请参阅我之前的文章 “Elasticsearch: analyzer”。文本分析通常应用于你建立索引时的所有文档以及发送给 Elasticsearch 的所有查询。在进行同义词搜索时,我们有如下的几种方案: 在建立索引时 (indexing),通过 analyzer 建

Elastic 中国社区官方博客 9463

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Elasticsearch 同义词搜索技术详解

在Elasticsearch中,同义词搜索是一种强大的功能,它允许系统识别具有相同或相似含义的不同词语。这项功能对于提升搜索体验和扩大搜索结果范围至关重要。 ### 同义词搜索的核心价值 1. **提升搜索相关性**:通过识别表达相同概念的不同术语,找到更多相关文档 2. **领域术语优化**:让用户可以使用他们更熟悉的术语进行搜索 3. **容错处理**:可以定义常见拼写错误,自动纠正用户输...

gitblog_01065的博客 457

搜索引擎中同义词的挖掘及使用

  用户在使用搜索引擎过程中,由于表述不清晰或者查询词与索引库描述不一致,为了能召回更多更优质的结果展示给用户。这时就需要对用户查询进行分析,包括词权、同义词、纠错等技术,对原查询进行处理。通常搜索引擎中对同义词的处理,线下挖掘同义词词典,线上加载词典,但由于检索系统应用同义词时词典存在部分质量不好、或者本来质量好但是应用同义词更上下文有很强的关联性,并不一定适用,因此同义词主要包括两大方面,同...

weixin_30721899的博客 1984

IK如何实现同义词搜索

  转载请声明出处,谢谢。翻译也很辛苦      solr学习交流扣扣群340954928   IK如何实现同义词搜索     如何通过IK实现   <!--[if !supportLists]-->1、  <!--[endif]-->在schema.xml中配置            <fieldType name="text_ik...

老男人 1195

Solr 同义词搜索 synonyms

Solr同义词搜索是一个很好的功能实现,解决了产品需求中很大的问题,如:搜索用户搜索"刮胡刀" 更好的展示结果是把 "刮胡刀"跟"剃须刀"都显示给用户,这样就可以达到更好的效果。下面讲下具体实现: solr.SynonymFilterFactory Creates SynonymFilter Matches strings of tokens and replaces them with o...

iteye_5347的博客 244

同义词 - 搜索引擎

同义词分类:索引同义词和搜索同义词。 索引同义词和搜索同义词的关系:时间和空间互换,任何词都可以放在搜索同义词中也可以放在索引同义词中,

1299

搜索引擎是如何处理同义词?

对于SEO人员而言,我们非常清楚,我们所撰写的一篇篇优质的文章,实际上,都是通过中文分词之后,针对整个关键词词库经过合理的算法排序,存储在搜索引擎索引库。 当我们有相关查询需求的时候,搜索引擎开始通过一些列算法调用相关的数据反馈在搜索结果中,而这其中有一个特别重要的问题就是:SEO人员经常忽略网站关键词列表中的同义词,这也是一些SEO培训教程,经常忽略的地方。 那么,搜索引擎是如何处理同义...

蝙蝠侠IT 1093

Elasticsearch学习笔记6: 同义词搜索实现

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34112181的博客 867
上一篇: 搞互联网压力真大,我需要给自己减减压
下一篇: Cache 和 Buffer 都是缓存,主要区别是什么?
码洞
博客等级 码龄10年 41粉丝 137原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值