elasticsearch
es基本概念
es术语介绍
- 文档Document
- 用户存储在es中的数据文档
- 索引Index
- 由具有相同字段的文档列表组成
- 节点node
- 一个Elasticsearch的运行实例,是集群的构成单元
- 集群Cluster
- 由一个或多个节点组成,对外提供服务
document介绍
- json object,由字段(field)组成,常见数据类型如下:
- 字符串:text,keyword
- 数值型:long,integer,short,byte,double,float,half_float,scaled_float
- 布尔:boolean
- 日期:date
- 二进制:binary
- 范围类型:integer_range,float_range,long_range,double_range,date_range
- 每个文档有唯一的id标识
- 自行指定
- es自动生成
- 元数据,用于标注文档的相关信息
- _index:文档所在的索引名
- _type:文档所在的类型名
- _id:文档唯一id
- _uid:组合id,由_type和_id组成(6.x _type不再起作用,同_id一样)
- _source:文档的原始json数据,可以从这里获取每个字段的内容
- _all:整合所有字段内容到该字段,默认禁用
Index介绍
- 索引中存储具有相同结构的文档(Document)
- 每个索引都有自己的mapping定义,用于定义字段名和类型
- 一个集群可以有多个索引,比如:
- nginx日志存储的时候可以按照日期每天生成一个索引来存储
rest api
- elasticsearch集群对外提供restful api
- rest-representational state transfer
- uri指定资源,如index、document等
- http method指明资源操作类型,如GET、POST、PUT、DELETE等
- 常用两种交互方式
- curl命令行
- Kibana Devtools
索引API
- es有专门的index api,用于创建、更新、删除索引配置等
- 创建索引api如下:
PUT /test_index
文档api
- es有专门的Document API
- 创建文档
- 查询文档
- 更新文档
- 删除文档
- 创建文档
- 指定id创建文档api如下:
PUT /test_index/doc/1 { "username":"alfred", "age":1 }
创建文档时,如果索引不存在,es会自动创建对应的index和type - 不指定id创建文档api如下:
POST /test_index/doc { "username":"tom", "age":20 }
- 查询文档
- 指定要查询的文档id
GET /test_index/doc/1
- 搜索所有文档,用到_search,如下:
GET /test_index/doc/_search { "query":{ "term":{ "_id":"1" } } }
查询语句,json格式,放在http body中发送到es
批量创建文档api
- es允许一次创建多个文档,从而减少网络传输开销,提升写入速率
- endpoint为_bulk,如下:
POST _bulk {"index":{"_index":"test_index","_type":"doc","_id":"3"}} {"username":"alfred","age":10} {"delete":{"_index":"test_index","_type":"doc","_id":"1"}}
批量查询文档API
- es允许一次查询多个文档
- endpoint为_mget,如下:
GET /_mget { "doc":[ { "_index":"test_index", "_type":"doc", "_id":"1" }, { "_index":"test_index", "_type":"doc", "_id":"2" } ] }
索引
正排索引与倒排索引
- 正排索引
- 文档id到文档内容、单词的关联关系
文档id | 文档内容 |
1 | elasticsearch是最流行的搜索引擎 |
2 | PHP是世界上最好的语言 |
3 | 搜索引擎是如何诞生的 |
- 倒排索引
- 单词到文档id的关联关系
单词 | 文档ID列表 |
elasticsearch | 1 |
流行 | 1 |
搜索引擎 | 1,3 |
世界 | 2 |
倒排索引-查询流程
- 查询包含"搜索引擎"的文档
- 通过倒排索引获得"搜索引擎"对应的文档ID有1和3
- 通过正排索引查询1和3的完整内容
- 返回用户最终结果
倒排索引详解
- 倒排索引是搜索引擎的核心,主要包含两部分:
- 单词字典(Term Dictionary)
- 倒排列表(Posting List)
- es存储的是一个json格式的文档,其中包含多个字段,每个字段会有自己的倒排索引
单词词典
- 单词字典(Term Dictionary)是倒排索引的重要组成部分
- 记录所有文档的单词,一般都比较大
- 记录单词到倒排列表的关联信息
- 单词字典的实现一般是用B+ Tree
倒排列表
- 倒排列表记录了单词对应的文档集合,由倒排索引项组成
- 倒排索引项主要包含如下信息:
- 文档ID,用于获取原始信息
- 单词频率,记录该单词在该文档中的出现次数,用于后续相关性算分
- 位置,记录单词在该文档中的分词位置(多个),用于做词语搜索
- 偏移,记录单词在文档的开始和结束位置,用于做高亮显示
分词
- 分词是指将文本转换成一系列单词的过程,也叫作文本分析,在es里面称为analysis
分词器
- 分词器是es中专门处理分词的组件,英文为analy,它的组成如下:
- 针对tokenizer处理的单词进行再加工,比如转小写、删除或新增等处理
- 将原始文本按照一定规则切分为单词
- 针对原始文本进行处理,比如去除HTML特殊标记符
- Character Filters
- Tokenizer
- Token Filters
Analyize API
- es提供了一个测试分词的api接口,方便验证分词效果,endpoint是_analyze
- 可以直接指定analyzer进行测试
- 可以直接指定索引中的字段进行测试
- 可以自定义分词器进行测试
- 直接指定analyzer进行测试,接口如下:
POST _analyze { "analyzer":"standard", #分词器 "text":"hello,world" #测试文本 }
- 自定义分词器进行测试,接口如下:
POST _analyze { "tokenizer":"standard", "filterf":["lowercase"], #自定义analyzer "text":"hello world" }
预定义的分词器
- es自带如下的分词器
- Standard
- Simple
- Whitespace
- Stop
- Keyword
- Pattern
- Language
- Standard Analyzer
- 按词切分,支持多语言
- 小写处理
- 默认分词器
- 其组成如下,特性为:
- Simple Analyzer
- 按照非字母切分
- 小写处理
- 其组成如下,特性为:
- Whitespace Analyzer
- 按照空格切分
- 其组成如下,特性为:
- Stop Analyzer
- 相比Simple Analyzer多了stop Word处理
- Stop Word指语气助词等修饰性的词语,比如the、an、的、这等等
- 其组成如图,特性为:
- Keyword Analyzer
- 不分词,直接将输入作为一个单词输出
- 其组成如下,特性为:
- Pattern Analyze
- 通过正则表达式自定义分隔符
- 默认是\W+,即非字词的符号作为分隔符
- 其组成如下,特性为:
- language Analyze
- 提供了30+常见语言的分词器
- Arabic,Armenian,basque,bengali,Brazilian,Bulgarian,catAlan,cjk,Czech,Danish,Dutch,English...
中文分词
- 难点
- 乒乓球拍/卖/完了
- 乒乓球/拍卖/完了
- 中文分词指的是将一个汉字序列切分成一个一个单独的词。在英文中,单词之间是以空格作为自然分界符,汉语中没有一个形式上的分界符
- 上下文不同,分词结果迥异,比如交叉歧义问题,比如下面两种分词都合理
- 常用分词系统
- python中最流行的分词系统,支持分词和词性标注
- 支持繁体分词、自定义词典、并行分词等
- https://github.com/singlee/elasticsearch-jieba-plugin
- 实现中英文单词的切分,支持ik_smart、ik_maxword等模式
- 可自定义词库,支持热更新分词词典
- https://github.com/medcl/elasticsearch-analysis-ik
- IK
- jieba
- 基于自然语言处理的分词系统
- THU Lexical Analyzer for Chinese,由清华大学自然原因处理与社会人文计算实验室研制推出的一套中文词法分析工具包,具有中文分词和词性标注功能
- https://github.com/microbun/elasticsearch-thulac-plugin
- 由一系列模型与算法组成的Java工具包,目标是普及自然语言处理在生产环境中的应用
- https://github.com/hankcs/HanLP
- Hanlp
- THULAC
自定义分词
- 当自带的分词无法满足需求时,可以自定义分词
- 通过自定义Character Filters、Tokenizer Filter实现
- Character Filters
- HTML Strip去除html标签和转换html实体
- Mapping进行字符替换操作
- Pattern Replace进行正则匹配替换
- 在Tokenizer之前对原始文本进行处理,比如增加、删除或替换字符等
- 自带的如下:
- 会影响后续Tokenizer解析的position和offset信息
- Character Filters测试时可以采用如下api:
POST _analyze { "tokenizer":"keyword", #keyword类型的Tokenizer可以直接看到输出结果 "char_filter":["html_strip"], #指明要使用的char_filter "text":"<p>I'm so <b>happy</b>!</p>" }
- Tokenizer
- standard按照单词进行分割
- letter按照非字符类进行分割
- whitespace按照空格进行分割
- UAX URL Email按照standard分割,但不会分割邮箱和url
- NGram和Edge NGram连词分割
- Path Hierarchy按照文件路径进行分割
- 将原始文本按照一定规则且分为单词(term or token)
- 自带的如下:
- Tokenizer测试时可以采用如下api:
POST _analyze { "tokenizer":"path_hierarchy", "text":"/one/two/three" }
- Token Filters
- lowercase将所有term转换为小写
- stop删除stop words
- NGram和Edge NGram连词分割
- Synonym添加近义词的term
- 对于Tokenizer输出的单词(term)进行增加、删除、修改等操作
- 自带的如下:
- Filter测试时可以采用如下api:
POST _analyze { "text":"a hello world", "tokenizer":"standard", "filter":[ "stop", "lowercase", { "type":"ngram", "min_gram":4, "max_gram":4 } ] }
自定义分词的api
- 自定义分词的api
- 自定义分词需要在索引的配置中设定,如下所示:
PUT test_index { "settings":{ "analysis":{ "char_filter":{}, "tokenizer":{}, "filter":{}, "analyzer":{} } } }
分词使用说明
- 分词会在如下两个时机使用:
- 创建或更新文档时(Index Time),会对相应的文档进行分词处理
- 查询时(Search Time),会对查询语句进行分词
- 索引时分词是通过配置Index Mapping中每个字段的analyzer属性实现的,如下:
- 不指定分词时,默认使用standard
PUT test_index { "mappings":{ "doc":{ "properties":{ "title":{ "type":"text", "analyzer":"whitespace" #指定分词器 } } } } }
- 查询时分词的指定方式有如下几种:
- 查询时通过analyzer指定分词器
POST test_index/_search { "query":{ "match":{ "message":{ "query":"hello", "analyzer":"standard" } } } }
- 通过index mapping设置search_analyzer实现
PUT test_index { "mappings":{ "doc":{ "properties":{ "title":{ "type":"text", "analyzer":"whitespace", "search_analyzer":"standard" } } } } }
- 一般不需要特别指定查询时分词器,直接使用索引时分词器即可,否则会出现无法匹配的情况下
分词使用建议
- 明确字段是否需要分词,不需要分词的字段就将type设置为keyword,可以节省空间和提高写性能
- 善用_analyze API,查看文档的具体分词结果
- 动手测试