推广 热搜: 行业  设备    系统  参数  经纪    教师  机械  中国 

ES倒排索引与分词详解

   日期:2024-11-01     作者:caijiyuan    xhstdz   评论:0    移动:http://changmeillh.xhstdz.com/mobile/news/80.html
核心提示:正排索引:文档id到单词的关联关系倒排索引:单词到文档id的关联关系示例:对以下三个文档去除停用词后构造倒排索引倒排索引-查
  • 正排索引:文档id到单词的关联关系
  • 倒排索引:单词到文档id的关联关系

示例:
对以下三个文档去除停用词后构造倒排索引

ES倒排索引与分词详解

倒排索引-查询过程

查询包含“搜索引擎”的文档

  1. 通过倒排索引获得“搜索引擎”对应的文档id列表,有1,3
  2. 通过正排索引查询1和3的完整内容
  3. 返回最终结果

倒排索引-组成

  • 单词词典(Term Dictionary)
  • 倒排列表(Posting List)

单词词典(Term Dictionary)

单词词典的实现一般用B+树,B+树构造的可视化过程网址: B+ Tree Visualization

关于B树和B+树

  1. 维基百科-B树
  2. 维基百科-B+树
  3. B树和B+树的插入、删除图文详解

倒排列表(Posting List)

  • 倒排列表记录了单词对应的文档集合,有倒排索引项(Posting)组成
  • 倒排索引项主要包含如下信息:
    1. 文档id用于获取原始信息
    2. 单词频率(TF,Term Frequency),记录该单词在该文档中出现的次数,用于后续相关性算分
    3. 位置(Posting),记录单词在文档中的分词位置(多个),用于做词语搜索(Phrase Query)
    4. 偏移(Offset),记录单词在文档的开始和结束位置,用于高亮显示

B+树内部结点存索引,叶子结点存数据,这里的 单词词典就是B+树索引,倒排列表就是数据,整合在一起后如下所示

note:
B+树索引中文和英文怎么比较大小呢?unicode比较还是拼音呢?

ES存储的是一个JSON格式的文档,其中包含多个字段,每个字段会有自己的倒排索引

分词是将文本转换成一系列单词(Term or Token)的过程,也可以叫文本分析,在ES里面称为Analysis

分词器是ES中专门处理分词的组件,英文为Analyzer,它的组成如下:

  • Character Filters:针对原始文本进行处理,比如去除html标签
  • Tokenizer:将原始文本按照一定规则切分为单词
  • Token Filters:针对Tokenizer处理的单词进行再加工,比如转小写、删除或增新等处理

分词器调用顺序

ES提供了一个可以测试分词的API接口,方便验证分词效果,endpoint是_analyze

  • 可以直接指定analyzer进行测试
  • 可以直接指定索引中的字段进行测试
    • 可以自定义分词器进行测试
    • ES自带的分词器有如下:

      • Standard Analyzer
        • 默认分词器
        • 按词切分,支持多语言
        • Simple Analyzer
          • 按照非字母切分
          • Whitespace Analyzer
            • 空白字符作为分隔符
            • Stop Analyzer
              • 相比Simple Analyzer多了去除请用词处理
              • 停用词指语气助词等修饰性词语,如the, an, 的, 这等
              • Keyword Analyzer
                • 不分词,直接将输入作为一个单词输出
                • Pattern Analyzer
                  • 通过正则表达式自定义分隔符
                  • 默认是W+,即非字词的符号作为分隔符
                  • Language Analyzer
                    • 提供了30+种常见语言的分词器

                    示例:停用词分词器

                    结果

                    • 难点
                      • 中文分词指的是将一个汉字序列切分为一个一个的单独的词。在英文中,单词之间以空格作为自然分界词,汉语中词没有一个形式上的分界符
                      • 上下文不同,分词结果迥异,比如交叉歧义问题
                      • 常见分词系统
                        • IK:实现中英文单词的切分,可自定义词库,支持热更新分词词典
                        • jieba:支持分词和词性标注,支持繁体分词,自定义词典,并行分词等
                        • Hanlp:由一系列模型与算法组成的Java工具包,目标是普及自然语言处理在生产环境中的应用
                        • THUAC:中文分词和词性标注

                        安装ik中文分词插件

                        • ik测试 - ik_smart
                          • ik测试 - ik_max_word
                            • ik两种分词模式ik_max_word 和 ik_smart 什么区别?
                              • ik_max_word: 会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,会穷尽各种可能的组合;

                              • ik_smart: 会做最粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”。

                                当自带的分词无法满足需求时,可以自定义分词,通过定义Character Filters、Tokenizer和Token Filters实现

                                Character Filters

                                • 在Tokenizer之前对原始文本进行处理,比如增加、删除或替换字符等
                                • 自带的如下:
                                  • HTML Strip Character Filter:去除HTML标签和转换HTML实体
                                  • Mapping Character Filter:进行字符替换操作
                                  • Pattern Replace Character Filter:进行正则匹配替换
                                  • 会影响后续tokenizer解析的position和offset信息

                                  Character Filters测试

                                  Tokenizers

                                  • 将原始文本按照一定规则切分为单词(term or token)
                                    • standard 按照单词进行分割
                                    • letter 按照非字符类进行分割
                                    • whitespace 按照空格进行分割
                                    • UAX URL Email 按照standard进行分割,但不会分割邮箱和URL
                                    • Path Hierarchy 按照文件路径进行分割

                                    Tokenizers 测试

                                    Token Filters

                                    • 对于tokenizer输出的单词(term)进行增加、删除、修改等操作
                                      • lowercase 将所有term转为小写
                                      • stop 删除停用词
                                      • Synonym 添加近义词的term

                                      Token Filters测试

                                      自定义分词

                                      自定义分词需要在索引配置中设定 char_filter、tokenizer、filter、analyzer等

                                      自定义分词示例:

                                      • 分词器名称:my_custom
                                      • 过滤器将token转为大写
                                      • 自定义分词器测试

                                        分词使用说明

                                        分词会在如下两个时机使用:

                                        • 创建或更新文档时(Index Time),会对相应的文档进行分词处理
                                        • 查询时(Search Time),会对查询语句进行分词
                                          • 查询时通过analyzer指定分词器
                                          • 通过index mapping设置search_analyzer实现
                                          • 一般不需要特别指定查询时分词器,直接使用索引分词器即可,否则会出现无法匹配的情况

                                          分词使用建议

                                          • 明确字段是否需要分词,不需要分词的字段就将type设置为keyword,可以节省空间和提高写性能
                                          • 善用_analyze API,查看文档的分词结果
                                          • 分析 包含下面的过程:

                                            • 首先,将一块文本分成适合于倒排索引的独立的 词条 ,
                                            • 之后,将这些词条统一化为标准格式以提高它们的“可搜索性”,或者 recall

                                            分析器执行上面的工作。 分析器 实际上是将三个功能封装到了一个包里:

                                            字符过滤器

                                            首先,字符串按顺序通过每个 字符过滤器 。他们的任务是在分词前整理字符串。一个字符过滤器可以用来去掉HTML,或者将  转化成 `and`。

                                            其次,字符串被 分词器 分为单个的词条。一个简单的分词器遇到空格和标点的时候,可能会将文本拆分成词条。

                                            Token 过滤器

                                            最后,词条按顺序通过每个 token 过滤器 。这个过程可能会改变词条(例如,小写化  ),删除词条(例如, 像  等无用词),或者增加词条(例如,像  和  这种同义词)。

                                            Elasticsearch提供了开箱即用的字符过滤器、分词器和token 过滤器。 这些可以组合起来形成自定义的分析器以用于不同的目的。我们会在 自定义分析器 章节详细讨论。

                                            但是, Elasticsearch还附带了可以直接使用的预包装的分析器。 接下来我们会列出最重要的分析器。为了证明它们的差异,我们看看每个分析器会从下面的字符串得到哪些词条:

                                            "Set the shape to semi-transparent by calling set_trans(5)"

                                            标准分析器

                                            标准分析器是Elasticsearch默认使用的分析器。它是分析各种语言文本最常用的选择。它根据 Unicode 联盟 定义的 单词边界 划分文本。删除绝大部分标点。最后,将词条小写。它会产生

                                            set, the, shape, to, semi, transparent, by, calling, set_trans, 5

                                            简单分析器

                                            简单分析器在任何不是字母的地方分隔文本,将词条小写。它会产生

                                            set, the, shape, to, semi, transparent, by, calling, set, trans

                                            空格分析器

                                            空格分析器在空格的地方划分文本。它会产生

                                            Set, the, shape, to, semi-transparent, by, calling, set_trans(5)

                                            语言分析器

                                            特定语言分析器可用于 很多语言。它们可以考虑指定语言的特点。例如,  分析器附带了一组英语无用词(常用单词,例如  或者  ,它们对相关性没有多少影响),它们会被删除。 由于理解英语语法的规则,这个分词器可以提取英语单词的 词干 。

                                             分词器会产生下面的词条:

                                            set, shape, semi, transpar, call, set_tran, 5

                                            注意看  和  已经变为词根格式。

                                            当我们 索引 一个文档,它的全文域被分析成词条以用来创建倒排索引。 但是,当我们在全文域 搜索 的时候,我们需要将查询字符串通过 相同的分析过程 ,以保证我们搜索的词条格式与索引中的词条格式一致。

                                            全文查询,理解每个域是如何定义的,因此它们可以做 正确的事:

                                            • 当你查询一个 全文 域时, 会对查询字符串应用相同的分析器,以产生正确的搜索词条列表。
                                            • 当你查询一个 精确值 域时,不会分析查询字符串, 而是搜索你指定的精确值。

                                            现在你可以理解在 开始章节 的查询为什么返回那样的结果:

                                            •  域包含一个精确值:单独的词条 `2014-09-15`。
                                            •  域是一个全文域,所以分词进程将日期转化为三个词条: `2014`, `09`, 和 `15`。

                                            当我们在  域查询  :

                                            GET /_search?q=2014              # 12 results
                                            	

                                            当我们在  域查询  中 任意 词条的查询。这也会匹配所有12条推文,因为它们都含有  :

                                            GET /_search?q=2014-09-15        # 12 results !
                                            	

                                            当我们在  域查询 `2014-09-15`,它寻找 精确 日期,只找到一个推文:

                                            GET /_search?q=date:2014-09-15   # 1  result
                                            	

                                            当我们在  域查询 `2014`,它找不到任何文档,因为没有文档含有这个精确日志:

                                            GET /_search?q=date:2014         # 0  results !
                                            	

                                            有些时候很难理解分词的过程和实际被存储到索引中的词条,特别是你刚接触 Elasticsearch。为了理解发生了什么,你可以使用  API 来看文本是如何被分析的。在消息体里,指定分析器和要分析的文本:

                                            GET /_analyze
                                            	"analyzer": "standard",
                                            	"text": "Text to analyze"
                                            	

                                            结果中每个元素代表一个单独的词条:

                                            {
                                            	"tokens": [
                                            	"token":        "text",
                                            	"start_offset": 0,
                                            	"end_offset":   4,
                                            	"position":     1
                                            	"token":        "to",
                                            	"start_offset": 5,
                                            	"end_offset":   7,
                                            	"position":     2
                                            	"token":        "analyze",
                                            	"start_offset": 8,
                                            	"end_offset":   15,
                                            	"position":     3
                                            	]
                                            	}

                                             是实际存储到索引中的词条。  指明词条在原始文本中出现的位置。  和  指明字符在原始字符串中的位置。

                                            每个分析器的  值都不一样,可以忽略它们。它们在Elasticsearch中的唯一作用在于 token 过滤器。

                                             API 是一个有用的工具,它有助于我们理解Elasticsearch索引内部发生了什么,随着深入,我们会进一步讨论它。

                                            当Elasticsearch在你的文档中检测到一个新的字符串域 ,它会自动设置其为一个全文  域,使用  分析器对它进行分析。

                                            你不希望总是这样。可能你想使用一个不同的分析器,适用于你的数据使用的语言。有时候你想要一个字符串域就是一个字符串域--不使用分析,直接索引你传入的精确值,例如用户ID或者一个内部的状态域或标签。

                                            要做到这一点,我们必须手动指定这些域的映射。

本文地址:http://changmeillh.xhstdz.com/news/80.html    物流园资讯网 http://changmeillh.xhstdz.com/ , 查看更多

特别提示:本信息由相关用户自行提供,真实性未证实,仅供参考。请谨慎采用,风险自负。

 
 
更多>同类最新文章
0相关评论

文章列表
相关文章
最新动态
推荐图文
最新文章
点击排行
网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报  |  鄂ICP备2020018471号