倒排索引、分词、同义词
倒排索引
- 正排索引:文档ID =>文档内容和单词
- 倒排索引:词条 =>文档ID
- 倒排索引组成:
- 词条字典(Term Dictionary),记录所有的词条与倒排列表的映射关系。这个字典很大,通过B+树或哈希拉链法实现,以满足高性能的插入与查询。
- 倒排列表(Posting List),由倒排索引项组成,包含如下信息:
- 文档ID
- 词频(TF):该单词在文档中出现的次数,用于相关性评分
- 位置(Position):单词在文档中分词的位置(也就是第几个分词),用于语句搜索(phrase query)
- 偏移(Offset):记录单词的开始结束位置,实现高亮显示(从第几个字符开始,到第几个字符结束)
- ES的倒排索引:
- ES文档的每个字段,默认都有自己的倒排索引
- 可以通过mappings,指定某些字段不做索引,以节省存储空间,但会导致该字段无法被搜索。
分词
文本分析(Analysis),就是把全文转换成一系列词条(term / token)的过程(也叫分词)。文本分析是通过分词器(Analyzer)实现的。
https://www.elastic.co/guide/en/elasticsearch/reference/7.2/analysis.html
分词器有两个作用:
- 数据写入时转换词条
- 分析查询语句
ES内置了多种分词器:https://www.elastic.co/guide/en/elasticsearch/reference/7.2/analysis-analyzers.html
在mapping中,每个text
字段都可以指定专门的分词器:
PUT {index}
{"mappings": {"properties": {"{field}": {"type": "text","analyzer": "{standard}" // 指定分词器}}}
}
说明:已经存在的索引执行上述操作会报错。可以在创建索引时指定。standard
分词器是默认的分词器。
通常情况下,创建(index)和查询(search)时,应该使用同样的分词器。执行全文检索时,比如match
查询,会在mapping中为每个字段查找分词器。在查询具体字段时使用何种分词器,遵循如下查找顺序:
- 查询条件有指定
analyzer
- mapping中的
search_anylyzer
参数 - mapping中的
analyzer
参数 - 索引设置中的
default_search
- 索引设置中的
default
standard
分词器
分词器由以下三部分组合而成:
Character Filters:处理原始文本,比如去除html标签。一个分词器可以没有或拥有多个char filter。
Tokenizer:接收上一步处理后的文本流,按照规则切分出词条并输出,比如:
whitespace
按空格切分词条keyword
不做分词,直接作为关键词path_hierarchy
, 按路径切分,保证搜索任意一级目录都可以搜索到结果
更多类别参考官网,每个分词器必须有一个tokenizer。
Token Filters:接收词条流,进行再加工,可能会添加、删除、或者变更词条。比如:
lowercase
将所有的词条转为小写stop
将停顿词(比如,the, in, on)从词条流中移除synonym
往词条流中引入同义词multiplexer
一个单词触发多个词条(应用多个过滤器,每个过滤器触发一个),重复的词条会被去除。建议:将同义词过滤器追加到每个multiplexer过滤器列表后面,不要放在multiplexer之后,以避免异常。建议具体见官网底部的note
更过token filter类别可以参考官网,一个分词器可以没有或拥有多个token filter
通过组合以上三部分,我们也可以自定义分词器。
###analyze接口
analyze
接口可以用来执行文本分析处理,并查看分词结果,比如:
GET _analyze
{"analyzer": "standard","text": "hello world"
}
使用standard
分词器对文本进行分词,返回结果如下:
{"tokens" : [{"token" : "hello","start_offset" : 0,"end_offset" : 5,"type" : "<ALPHANUM>","position" : 0},{"token" : "world","start_offset" : 6,"end_offset" : 11,"type" : "<ALPHANUM>","position" : 1}]
}
自定义分词
也可以自己定义分词器,其实就是组合tokenizer, token filter 和 char filer,比如:
示例1:自定义token filter
POST _analyze
{"tokenizer": "standard","filter": [ "lowercase", "asciifolding" ],"text": "Is this déja vu?"
}
示例2:自定义char_filter
POST _analyze
{"tokenizer": "standard","char_filter": [{"type": "mapping","mappings": ["- => _"] // 将中划线替换为下划线, 甚至可以将emoji表情替换为单词}],"text": "123-456, hello-world"
}// 结果如下:
{"tokens" : [{"token" : "123_456","start_offset" : 0,"end_offset" : 7,"type" : "<NUM>","position" : 0},{"token" : "hello_world","start_offset" : 9,"end_offset" : 20,"type" : "<ALPHANUM>","position" : 1}]
}
也可以为某个索引(集)自定义分词器:
put forum
{"settings": {"analysis": {"analyzer": {"my_analyzer": { // 自定义分词器名字"type": "custom","tokenizer": "standard","filter": ["lowercase","asciifolding"]}}}},"mappings": {"properties": {"title": {"type": "text","analyzer": "my_analyzer" // 使用自定义分词器}}}
}
测试分词效果:
GET forum/_analyze
{"analyzer": "my_analyzer","text": "Mr déjà"
}
分词结果如下:
{"tokens" : [{"token" : "mr","start_offset" : 12,"end_offset" : 14,"type" : "<ALPHANUM>","position" : 3},{"token" : "deja","start_offset" : 15,"end_offset" : 19,"type" : "<ALPHANUM>","position" : 4}]
}
mapping自定义分词器完全版:
{'settings': {'analysis': {'analyzer': { # 自定义analyzer: 可以使用下面自定义的tokenizer, char_filter,token_filter 等内容'my_analyzer': {'type': 'custom','char_filter': 'my_char_flt','tokenizer': 'my_tokenizer','filter': ['my_flt'], # token_filter}},'char_filter': { # 自定义 char_filter'my_char_flt': {}},'tokenizer': { # 自定义 tokenizer'my_tokenizer': {}},'filter': { # 自定义 token_filter'my_flt': {'type': 'synonym','synonyms_path': 'xxxxx'}},# "search_analyzer": {} # 也可以定义搜索分词器, 同analyzer},},'mappings': {'properties': {'content': {'type': 'text','analyzer': 'my_analyzer', # 使用自定义的分词器'search_analyzer': 'ik_smart',}}}
}
中文分词
ES内置的中文分词不好用,可以通过插件安装,比如非常流行的ik
分词:
.\elasticsearch-plugin.bat install https://github.com/medcl/elasticsearch-ana
lysis-ik/releases/download/v7.2.0/elasticsearch-analysis-ik-7.2.0.zip
装好后重启ES,查看插件列表:
GET _cat/plugins
返回刚刚安装的ik插件
DESKTOP-L1E59GR analysis-ik 7.2.0
ik支持一些自定义配置,比如扩展词典和热词更新。配置文件默认位置在es安装目录的config
ik目录下。具体配置可以参考:https://github.com/medcl/elasticsearch-analysis-ik
安装完成后,我们测试下效果:
GET _analyze
{"analyzer": "ik_smart","text": "创新空间的不朽传奇"
}
分词结果:
{"tokens" : [{"token" : "创新","start_offset" : 0,"end_offset" : 2,"type" : "CN_WORD","position" : 0},{"token" : "空间","start_offset" : 2,"end_offset" : 4,"type" : "CN_WORD","position" : 1},{"token" : "的","start_offset" : 4,"end_offset" : 5,"type" : "CN_CHAR","position" : 2},{"token" : "不朽","start_offset" : 5,"end_offset" : 7,"type" : "CN_WORD","position" : 3},{"token" : "传奇","start_offset" : 7,"end_offset" : 9,"type" : "CN_WORD","position" : 4}]
}
试试官网的例子,定义news索引的mapping:
PUT news
{"mappings": {"properties": {"content": {"type": "text","analyzer": "ik_max_word", "search_analyzer": "ik_smart"}}}
}
按照文档说明,索引一些doc进去:
PUT news/_doc/4
{"content": "中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首"
}
进行高亮查询:
POST news/_search
{"query": {"match": {"content": "中国"}},"highlight": {"pre_tags": "<bold>","post_tags": "</bold>","fields": {"content": {}}}
}
返回结果如下:
{"took" : 2,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 0.642793,"hits" : [{"_index" : "news","_type" : "_doc","_id" : "3","_score" : 0.642793,"_source" : {"content" : "中韩渔警冲突调查:韩警平均每天扣1艘中国渔船"},"highlight" : {"content" : ["中韩渔警冲突调查:韩警平均每天扣1艘<bold>中国</bold>渔船"]}},{"_index" : "news","_type" : "_doc","_id" : "4","_score" : 0.642793,"_source" : {"content" : "中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首"},"highlight" : {"content" : ["<bold>中国</bold>驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首"]}}]}
}
测试下来后,在索引阶段,建议使用ik_max_word
分词器,能更灵活的切割词条。
除了IK分词,还可以使用THULAC分词器,号称准确率目前最高。不过目前只更新到6.4,不知道7.2能否使用。
搜索时指定分词器
GET post001/_search
{"query": {"match": {"content": {"query": "考研","analyzer": "standard"}}},"highlight": {"fields": {"content": {}}}}
同义词图过滤器 Synonym Graph Token Filter
synonym_graph
词条过滤器(token filter)用于处理同义词。
注意:该过滤器仅适用于作为搜索分词器的一部分。如果想在索引期间应用同义词,需要使用标准的同义词过滤器
同义词可以使用配置文件指定,如下:
PUT /{index}
{"settings": {"index" : {"analysis" : {"analyzer" : {"search_synonyms" : { // 自定义分词器名字"tokenizer" : "whitespace","filter" : ["graph_synonyms"] // 使用自定义filter}},"filter" : {"graph_synonyms" : {"type" : "synonym_graph", // 指定类型为同义词图"synonyms_path" : "analysis/synonym.txt" // 指定同义词词库位置}}}}}
}
说明:同义词词库的位置是相对于config
目录的相对地址。另外以下参数也是可用的:
expand
默认为true
leninet
默认为false
,是否忽略同义词配置的解析异常,记住,如果设置为true
,只要那些无法被解析到同义词规则会被忽略。如下示例:
PUT /{test_index}
{"settings": {"index" : {"analysis" : {"analyzer" : {"synonym" : {"tokenizer" : "standard","filter" : ["my_stop", "synonym_graph"]}},"filter" : {"my_stop": {"type" : "stop","stopwords": ["bar"]},"synonym_graph" : {"type" : "synonym_graph","lenient": true,"synonyms" : ["foo, bar => baz"] // 手动定义同义词映射}}}}}
}
说明:bar在自定义的my_stop的filter中被剔除,但是在synonym_graph的filter中,foo => baz仍然被添加成功。但如果添加的是"foo, baz => bar", 那么什么也不会被添加到同义词列表。这时因为映射到目标单词"bar"本身作为停用词已被剔除。相似的,如果映射是"bar, foo, baz"并且expand
设置为false
,那么不会添加任何同义词映射,因为当expand
为false
时,目标映射是第一个单词,也就是"bar"。但是如果expand=true
,那么映射将会添加为"foo, baz => foo, baz",即所有词相互映射,除了停用词。
同义词配置文件如下:
# 空行和#号开头的都是注释# 近义词以 => 映射,这种映射会忽略模式中的 expand 参数
# 匹配到"=>"左侧的词条后,被替换为"=>"右侧的词条。
i-pod, i pod => ipod,
sea biscuit, sea biscit => seabiscuit# 近义词以逗号分隔,映射行为由模式中的expand参数决定。如此同样的近义词文件,可以用于不同的策略
ipod, i-pod, i pod
foozball , foosball
universe , cosmos
lol, laughing out loud# 当expand==true, "ipod, i-pod, i pod" 等价于:
ipod, i-pod, i pod => ipod, i-pod, i pod
# 当expand==false, "ipod, i-pod, i pod" 仅映射第一个单词, 等价于:
ipod, i-pod, i pod => ipod# 多个同义词映射将会合并
foo => foo bar
foo => baz
# 等价于:
foo => foo bar, baz
虽然可以直接在filter中使用synonyms
定义同义词,比如:
PUT /test_index
{"settings": {"index" : {"analysis" : {"filter" : {"synonym" : {"type" : "synonym_graph","synonyms" : [ // 直接定义"lol, laughing out loud","universe, cosmos"]}}}}}
}
但是对于大型的同义词集合,还是推荐使用synonyms_path
参数在文件中定义。
测试
定义mapping
PUT article
{"settings": {"index": {"analysis": {"analyzer": {"my_analyzer": {"tokenizer": "ik_max_word","filter": ["my_synonyms"]}},"filter": {"my_synonyms": {"type": "synonym_graph","synonyms_path": "analysis/synonyms.txt"}},"search_analyzer": "ik_smart"}}}
}
在ES的config/analysis
目录下新建synonyms.txt
文件,内容如下:
北京大学, 北大
索引一篇文档:
PUT article/_doc/1
{"content": "北京大学今年考研一飞冲天"
}
试着搜索:
GET article/_search
{"query": {"match": {"content": {"query": "北大"}}}
}
搜索结果:
{"took" : 0,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 1,"relation" : "eq"},"max_score" : 0.5753642,"hits" : [{"_index" : "article","_type" : "_doc","_id" : "1","_score" : 0.5753642,"_source" : {"content" : "北京大学今年考研一飞冲天"}}]}
}
同义词过滤器 Synonym Token Filter
同义词过滤器配置示例:
PUT /test_index
{"settings": {"index" : {"analysis" : {"analyzer" : {"my-synonym" : { // 自定义分词器名字"tokenizer" : "whitespace","filter" : ["my_synonym_fltr"] // 指定过滤器}},"filter" : {"my_synonym_fltr" : { // 自定义同义词过滤器名字"type" : "synonym", // type 为synonym,"synonyms_path" : "analysis/synonym.txt"}}}}}
}
其实同义词过滤器和以上面的同义词图过滤器配置用法都是一样的。区别如下:
- 前者
type=synonym
,后者type=synonym_graph
- 前者可以在文档索引期间使用,后者只能作为搜索分词的一部分。
另外在同义词图中的测试,将type更改后,测试仍然适用。
倒排索引、分词、同义词相关推荐
- elasticsearch analysis模块 自定义分词 拼音分词 同义词 停词
Analysis Analysis 解析器由三个模块=character filters(字符过滤器), tokenizers(标记器), and token filters(标记过滤器)组成 Ana ...
- Elasticsearch 自定义分词同义词环节的这个细节不大好理解......
1.问题引出 球友认证考试前一天晚上提问: 扩展背景描述: 这是 Elasticsearch 自定义分词 Text analysis 章节 Token filter reference 小节的 同义词 ...
- ES倒排索引与分词详解
倒排索引 正排索引:文档id到单词的关联关系 倒排索引:单词到文档id的关联关系 示例: 对以下三个文档去除停用词后构造倒排索引 image 倒排索引-查询过程 查询包含"搜索引擎" ...
- [大数据]-Fscrawler导入文件(txt,html,pdf,worf...)到Elasticsearch5.3.1并配置同义词过滤...
fscrawler是ES的一个文件导入插件,只需要简单的配置就可以实现将本地文件系统的文件导入到ES中进行检索,同时支持丰富的文件格式(txt.pdf,html,word...)等等.下面详细介绍下f ...
- 文本分类从入门到精通各种模型的学习——Jieba分词。
结巴中文分词 Python中文分词组件 四种分词模式 精确模式:试图把句子最精确的切开,适合文本分析. 全模式:把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义: 搜索引擎模式: ...
- 百度搜索引擎的工作原理 鏀惰棌鍒帮細 时间:2015-07-10 文章来源:马海祥博客 访问次数:4330 关于百度以及其它搜索引擎的工作原理,其实大家已经讨论过很多,但随着科技的进步、互联网
关于百度以及其它搜索引擎的工作原理,其实大家已经讨论过很多,但随着科技的进步.互联网业的发展,各家搜索引擎都发生着巨大的变化,并且这些变化都是飞快的,本文的目的,除了从百度官方的角度发出一些声音.纠正 ...
- ElasticSearch1-官方文档翻译(概念,搜索,聚合篇)
文章目录 全文搜索 1.Getting start basic concepts 搜索原理 倒排索引原理: 对索引 对文档 2. 搜索Search API 2.1 query string searc ...
- 谷粒商城微服务分布式高级篇ElasticSearch二——重要概念及原理
文章目录 面向文档 索引 分布式特性 分布式集群 集群健康 添加索引 增加故障转移 横向扩展 继续扩展 应对故障 数据结构 什么是文档? 文档元数据 _index _type _id 其他元数据 _s ...
- 技术干货 | 如何在 Electron 上实现 IM SDK 聊天消息全文检索
导读:在 IM 场景的客户端需求上,基于本地数据的全文检索(Full-text search)扮演着重要的角色.本文具体来聊聊网易云信是如何实现全文检索的. 文|李宁 网易云信高级前端开发工程师 所谓 ...
- LeetCode刷题遇到的小知识点总结
文章目录 1. 需要判断输入的两个参数的大小/长度 2. 数学分式的化简 3. 二叉树操作的小总结 4. MySQL分组内取前几名的问题 5. SQL中的小问题 6. 对哈希表的初步理解 (1)初步理 ...
最新文章
- Redis的两种持久化机制RDB和AOF
- python笔记之正则表达式
- php支持cs吗,关于composer、phpmd和phpcs于windows中的安装与使用方法
- 计算机网络太难?如何系统自学计算机网络?
- caffeine 读操作源码走读 为什么读这么快
- VS2008都出來了﹐看來我們升級VS2005的計划要改了。
- Spring Cloud EurekaService 服务部署服务注册与发现(一)
- 一个页面可以重复调用的TAB选项卡切换js代码 鼠标悬浮
- 【英语魔法俱乐部——读书笔记】 3 高级句型-简化从句倒装句(Reduced Clauses、Inverted Sentences) 【完结】...
- VMware下载以及安装教程
- codeforces 1520E Arranging The Sheep
- python求数独全解
- 解决QQ识图后复制文字然后将其粘贴到文件重命名中,总是显示重命名不成功
- 三甲:在线富文本编辑器的架构设计及实践
- python文本编辑器下载_python文本编辑器下载-TextPad下载v 8.2.0最新免费版-西西软件下载...
- Java分布式跟踪系统Zipkin(二):Brave源码分析-Tracer和Span
- 数据结构与算法之2-3-4树
- [收集整理]BT恶心诗全集
- 小小输入法—郑码学习
- 编译设备树时报错“arch/arm/boot/dts/imx50.dtsi:14:42:致命错误:dt-bindings/clock/imx5-clock/h:没有那个文件或目录”
热门文章
- (王道408考研操作系统)第五章输入/输出(I/O)管理-第一节1:I/O设备的概念和分类
- epoll 系列系统调用
- 1313. 解压缩编码列表
- Linux安装python3.7(Centos、Ubuntu)
- 转载-----Java Longest Palindromic Substring(最长回文字符串)
- 打造高效前端工作环境-tmuxinator
- JS中的数据类型(见《Jquery实战附录》)
- SharePoint2010 连接配置数据库字符串保存位置(转)
- 看几个源码,自己多做项目了!
- 屠杀机器人和无处不在的监控:AI是我们最大的生存威胁?