最新公告
  • 新注册用户请前往个人中心绑定邮箱以便接收相关凭证邮件!!!点击前往个人中心
  • 倒排索引与分词

    倒排索引

    • 正排索引:文档id到单词的关联关系
    • 倒排索引:单词到文档id的关联关系

    示例:

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

    image

    倒排索引-查询过程

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

    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+树的插入、删除图文详解

    image

    倒排列表(Posting List)

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

    image

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

    image

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

    分词

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

    image

    分词器

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

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

    分词器调用顺序

    image

    Analyze API

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

    • 可以直接指定analyzer进行测试

    image

    • 可以直接指定索引中的字段进行测试

    POST test_index/doc

    {

    “username”: “whirly”,

    “age”:22

    }

    POST test_index/_analyze

    {

    “field”: “username”,

    “text”: [“hello world”]

    }

    • 可以自定义分词器进行测试

    POST _analyze

    {

    “tokenizer”: “standard”,

    “filter”: [“lowercase”],

    “text”: [“Hello World”]

    }

    预定义的分词器

    ES自带的分词器有如下:

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

    示例:停用词分词器

    POST _analyze

    {

    “analyzer”: “stop”,

    “text”: [“The 2 QUICK Brown Foxes jumped over the lazy dog’s bone.”]

    }

    结果

    {

    “tokens”: [

    {

    “token”: “quick”,

    “start_offset”: 6,

    “end_offset”: 11,

    “type”: “word”,

    “position”: 1

    },

    {

    “token”: “brown”,

    “start_offset”: 12,

    “end_offset”: 17,

    “type”: “word”,

    “position”: 2

    },

    {

    “token”: “foxes”,

    “start_offset”: 18,

    “end_offset”: 23,

    “type”: “word”,

    “position”: 3

    },

    {

    “token”: “jumped”,

    “start_offset”: 24,

    “end_offset”: 30,

    “type”: “word”,

    “position”: 4

    },

    {

    “token”: “over”,

    “start_offset”: 31,

    “end_offset”: 35,

    “type”: “word”,

    “position”: 5

    },

    {

    “token”: “lazy”,

    “start_offset”: 40,

    “end_offset”: 44,

    “type”: “word”,

    “position”: 7

    },

    {

    “token”: “dog”,

    “start_offset”: 45,

    “end_offset”: 48,

    “type”: “word”,

    “position”: 8

    },

    {

    “token”: “s”,

    “start_offset”: 49,

    “end_offset”: 50,

    “type”: “word”,

    “position”: 9

    },

    {

    “token”: “bone”,

    “start_offset”: 51,

    “end_offset”: 55,

    “type”: “word”,

    “position”: 10

    }

    ]

    }

    中文分词

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

    安装ik中文分词插件

    # 在Elasticsearch安装目录下执行命令,然后重启es

    bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.3.0/elasticsearch-analysis-ik-6.3.0.zip

    # 如果由于网络慢,安装失败,可以先下载好zip压缩包,将下面命令改为实际的路径,执行,然后重启es

    bin/elasticsearch-plugin install file:///path/to/elasticsearch-analysis-ik-6.3.0.zip

    • ik测试 – ik_smart

    POST _analyze

    {

    “analyzer”: “ik_smart”,

    “text”: [“公安部:各地校车将享最高路权”]

    }

    # 结果

    {

    “tokens”: [

    {

    “token”: “公安部”,

    “start_offset”: 0,

    “end_offset”: 3,

    “type”: “CN_WORD”,

    “position”: 0

    },

    {

    “token”: “各地”,

    “start_offset”: 4,

    “end_offset”: 6,

    “type”: “CN_WORD”,

    “position”: 1

    },

    {

    “token”: “校车”,

    “start_offset”: 6,

    “end_offset”: 8,

    “type”: “CN_WORD”,

    “position”: 2

    },

    {

    “token”: “将”,

    “start_offset”: 8,

    “end_offset”: 9,

    “type”: “CN_CHAR”,

    “position”: 3

    },

    {

    “token”: “享”,

    “start_offset”: 9,

    “end_offset”: 10,

    “type”: “CN_CHAR”,

    “position”: 4

    },

    {

    “token”: “最高”,

    “start_offset”: 10,

    “end_offset”: 12,

    “type”: “CN_WORD”,

    “position”: 5

    },

    {

    “token”: “路”,

    “start_offset”: 12,

    “end_offset”: 13,

    “type”: “CN_CHAR”,

    “position”: 6

    },

    {

    “token”: “权”,

    “start_offset”: 13,

    “end_offset”: 14,

    “type”: “CN_CHAR”,

    “position”: 7

    }

    ]

    }

    • ik测试 – ik_max_word

    POST _analyze

    {

    “analyzer”: “ik_max_word”,

    “text”: [“公安部:各地校车将享最高路权”]

    }

    # 结果

    {

    “tokens”: [

    {

    “token”: “公安部”,

    “start_offset”: 0,

    “end_offset”: 3,

    “type”: “CN_WORD”,

    “position”: 0

    },

    {

    “token”: “公安”,

    “start_offset”: 0,

    “end_offset”: 2,

    “type”: “CN_WORD”,

    “position”: 1

    },

    {

    “token”: “部”,

    “start_offset”: 2,

    “end_offset”: 3,

    “type”: “CN_CHAR”,

    “position”: 2

    },

    {

    “token”: “各地”,

    “start_offset”: 4,

    “end_offset”: 6,

    “type”: “CN_WORD”,

    “position”: 3

    },

    {

    “token”: “校车”,

    “start_offset”: 6,

    “end_offset”: 8,

    “type”: “CN_WORD”,

    “position”: 4

    },

    {

    “token”: “将”,

    “start_offset”: 8,

    “end_offset”: 9,

    “type”: “CN_CHAR”,

    “position”: 5

    },

    {

    “token”: “享”,

    “start_offset”: 9,

    “end_offset”: 10,

    “type”: “CN_CHAR”,

    “position”: 6

    },

    {

    “token”: “最高”,

    “start_offset”: 10,

    “end_offset”: 12,

    “type”: “CN_WORD”,

    “position”: 7

    },

    {

    “token”: “路”,

    “start_offset”: 12,

    “end_offset”: 13,

    “type”: “CN_CHAR”,

    “position”: 8

    },

    {

    “token”: “权”,

    “start_offset”: 13,

    “end_offset”: 14,

    “type”: “CN_CHAR”,

    “position”: 9

    }

    ]

    }

    • 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测试

    POST _analyze

    {

    “tokenizer”: “keyword”,

    “char_filter”: [“html_strip”],

    “text”: [“<p>I&apos;m so <b>happy</b>!</p>”]

    }

    # 结果

    {

    “tokens”: [

    {

    “token”: “””

    I’m so happy!

    “””,

    “start_offset”: 0,

    “end_offset”: 32,

    “type”: “word”,

    “position”: 0

    }

    ]

    }

    Tokenizers

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

    Tokenizers 测试

    POST _analyze

    {

    “tokenizer”: “path_hierarchy”,

    “text”: [“/path/to/file”]

    }

    # 结果

    {

    “tokens”: [

    {

    “token”: “/path”,

    “start_offset”: 0,

    “end_offset”: 5,

    “type”: “word”,

    “position”: 0

    },

    {

    “token”: “/path/to”,

    “start_offset”: 0,

    “end_offset”: 8,

    “type”: “word”,

    “position”: 0

    },

    {

    “token”: “/path/to/file”,

    “start_offset”: 0,

    “end_offset”: 13,

    “type”: “word”,

    “position”: 0

    }

    ]

    }

    Token Filters

    • 对于tokenizer输出的单词(term)进行增加、删除、修改等操作
    • 自带的如下:
      • lowercase 将所有term转为小写
      • stop 删除停用词
      • Ngram 和 Edge NGram 连词分割
      • Synonym 添加近义词的term

    Token Filters测试

    POST _analyze

    {

    “text”: [

    “a Hello World!”

    ],

    “tokenizer”: “standard”,

    “filter”: [

    “stop”,

    “lowercase”,

    {

    “type”: “ngram”,

    “min_gram”: 4,

    “max_gram”: 4

    }

    ]

    }

    # 结果

    {

    “tokens”: [

    {

    “token”: “hell”,

    “start_offset”: 2,

    “end_offset”: 7,

    “type”: “<ALPHANUM>”,

    “position”: 1

    },

    {

    “token”: “ello”,

    “start_offset”: 2,

    “end_offset”: 7,

    “type”: “<ALPHANUM>”,

    “position”: 1

    },

    {

    “token”: “worl”,

    “start_offset”: 8,

    “end_offset”: 13,

    “type”: “<ALPHANUM>”,

    “position”: 2

    },

    {

    “token”: “orld”,

    “start_offset”: 8,

    “end_offset”: 13,

    “type”: “<ALPHANUM>”,

    “position”: 2

    }

    ]

    }

    自定义分词

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

    自定义分词示例:

    • 分词器名称:my_custom\
    • 过滤器将token转为大写

    PUT test_index_1

    {

    “settings”: {

    “analysis”: {

    “analyzer”: {

    “my_custom_analyzer”: {

    “type”: “custom”,

    “tokenizer”: “standard”,

    “char_filter”: [

    “html_strip”

    ],

    “filter”: [

    “uppercase”,

    “asciifolding”

    ]

    }

    }

    }

    }

    }

    自定义分词器测试

    POST test_index_1/_analyze

    {

    “analyzer”: “my_custom_analyzer”,

    “text”: [“<p>I&apos;m so <b>happy</b>!</p>”]

    }

    # 结果

    {

    “tokens”: [

    {

    “token”: “I’M”,

    “start_offset”: 3,

    “end_offset”: 11,

    “type”: “<ALPHANUM>”,

    “position”: 0

    },

    {

    “token”: “SO”,

    “start_offset”: 12,

    “end_offset”: 14,

    “type”: “<ALPHANUM>”,

    “position”: 1

    },

    {

    “token”: “HAPPY”,

    “start_offset”: 18,

    “end_offset”: 27,

    “type”: “<ALPHANUM>”,

    “position”: 2

    }

    ]

    }

    分词使用说明

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

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

    分词使用建议

    • 明确字段是否需要分词,不需要分词的字段就将type设置为keyword,可以节省空间和提高写性能
    • 善用_analyze API,查看文档的分词结果
    本站所有文章均由网友分享,仅用于参考学习用,请勿直接转载,如有侵权,请联系网站客服删除相关文章。若由于商用引起版权纠纷,一切责任均由使用者承担
    极客文库 » 倒排索引与分词

    常见问题FAQ

    如果资源链接失效了怎么办?
    本站用户分享的所有资源都有自动备份机制,如果资源链接失效,请联系本站客服QQ:2580505920更新资源地址。
    如果用户分享的资源与描述不符怎么办?
    可以联系客服QQ:2580505920,如果要求合理可以安排退款或者退赞助积分。
    如何分享个人资源获取赞助积分或其他奖励?
    本站用户可以分享自己的资源,但是必须保证资源没有侵权行为。点击个人中心,根据操作填写并上传即可。资源所获收益完全归属上传者,每周可申请提现一次。
    如果您发现了本资源有侵权行为怎么办?
    及时联系客服QQ:2580505920,核实予以删除。

    参与讨论

    • 184会员总数(位)
    • 3737资源总数(个)
    • 0本周发布(个)
    • 0 今日发布(个)
    • 572稳定运行(天)

    欢迎加入「极客文库」,成为原创作者从这里开始!

    立即加入 了解更多
    成为赞助用户享有更多特权立即升级