倒排索引
- 正排索引:文档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