1# @Time : 2020-05-27
2# @Language: Markdown
3# @Software: VS Code
4# @Author : Di Wang
5# @Email : [email protected]
把EPICS PV存入ES后,为了方便搜索,需要自定义analyzer。
ES 文本分析
基于https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis.html完成本文。
ES默认使用standard analyzer
对一段文本进行操作,如分词(根据空格拆分),单词还原(foxes
还原为fox
),去除停用词(移除the
,a
等冠词)等。除默认分析器还有一系列内置分析器(built-in analyzer
),用户也可以自定义分析器。
Analyzer概述
文本分析器结构
character filters, tokenizers, and token filters
,顾名思义,第一个是去除那些不想要的character,第二个是根据分隔符得到一组token,第三个是设置token的过滤和处理,下面详细讲。
使用时机
- 索引一个
text
的field时进行分析,称为index analyzer
- 调用search API进行检索时对要搜索的文本进行分析
search analyzer
大多数情况,使用同一个分析器。
如何设置分析器
对于index analyzer
,可以直接设置index
的默认分词器,也可以在mapping
里设置field
的分词器。
对于search analyzer
,可以在查询语句里指定分析器,也可以设置index
和 field
的搜索分析器,这其中有优先级,按顺序:
- 查询语句中指定的分析器
field
中指定的搜索分析器index
中指定的搜索分析器field
中指定的索引分析器- 默认的
standard analyzer
1PUT my_index
2{
3 "mappings": {
4 "properties": {
5 "title": {
6 "type": "text",
7 "analyzer": "whitespace",
8 "search_analyzer": "simple"
9 }
10 }
11 }
12}
13
14PUT my_index
15{
16 "settings": {
17 "analysis": {
18 "analyzer": {
19 "default": {
20 "type": "simple"
21 },
22 "default_search": {
23 "type": "whitespace"
24 }
25 }
26 }
27 }
28}
29GET my_index/_search
30{
31 "query": {
32 "match": {
33 "message": {
34 "query": "Quick foxes",
35 "analyzer": "stop"
36 }
37 }
38 }
39}
Stemming
把单词还原到其词根,be, are, and am
, mouse and mice
, foot and feet
有很多细节,不展开了。
如何测试分析器
如何配置ES自带的分析器
1PUT my_index
2{
3 "settings": {
4 "analysis": {
5 "analyzer": {
6 "std_english": {
7 "type": "standard",
8 "stopwords": "_english_"
9 }
10 }
11 }
12 },
13 "mappings": {
14 "properties": {
15 "my_text": {
16 "type": "text",
17 "analyzer": "standard",
18 "fields": {
19 "english": {
20 "type": "text",
21 "analyzer": "std_english"
22 }
23 }
24 }
25 }
26 }
27}
28
29POST my_index/_analyze
30{
31 "field": "my_text",
32 "text": "The old brown cow"
33}
34
35POST my_index/_analyze
36{
37 "field": "my_text.english",
38 "text": "The old brown cow"
39}
输出结果一个去除了the
,一个保留。
如何自定义分析器
1PUT my_index
2{
3 "settings": {
4 "analysis": {
5 "analyzer": {
6 "my_custom_analyzer": {
7 "type": "custom",
8 "char_filter": [
9 "emoticons"
10 ],
11 "tokenizer": "punctuation",
12 "filter": [
13 "lowercase",
14 "english_stop"
15 ]
16 }
17 },
18 "tokenizer": {
19 "punctuation": {
20 "type": "pattern",
21 "pattern": "[ .,!?]"
22 }
23 },
24 "char_filter": {
25 "emoticons": {
26 "type": "mapping",
27 "mappings": [
28 ":) => _happy_",
29 ":( => _sad_"
30 ]
31 }
32 },
33 "filter": {
34 "english_stop": {
35 "type": "stop",
36 "stopwords": "_english_"
37 }
38 }
39 }
40 }
41}
42
43POST my_index/_analyze
44{
45 "analyzer": "my_custom_analyzer",
46 "text": "I'm a :) person, and you?"
47}
自定义内容:
- 字符过滤器,把颜文字替换掉
- 分词器:根据标点符号分词
- 过滤器:大写字母变小写,然后去除英语停用词
输出结果: [ i'm, _happy_, person, you ]
看完这个其实就可以自定义了,毕竟EPICS PV一般都长这样:
LIiEV:evg0-EvtClk:FracSynFreq-SP
似乎设置:
作为分词器,然后大写转小写就搞定了。
内置分析器
Standard Analyzer
- 根据一个叫
Unicode Text Segmentation algorithm
的算法分隔单词,转小写,支持移除停用词。
- 根据一个叫
Simple Analyzer
- 不可配置,遇到不是字母的字符就分隔,转小写
Whitespace Analyzer
- 不可配置,遇到空格就分隔。
Stop Analyzer
- 比Simple Analyzer 多了移除停用词
Keyword Analyzer
- 什么也不干,把整段文字当作一个keyword,不可配置。就和
keyword
field一样。
- 什么也不干,把整段文字当作一个keyword,不可配置。就和
Pattern Analyzer
- 基于正则表达式,默认用的Java
\W+
,匹配任何non-word的字符,也就是[^a-zA-Z0-9_]
,用别的正则官方说可能导致速度很慢。支持转小写,设置停用词,设置停用词文件路径。
- 基于正则表达式,默认用的Java
Language Analyzer
- 支持不同的语言,懒得看细节了。
Fingerprint Analyzer
- 支持小写,去重,排序,移除停用词,以及
concatenated into a single token
(没懂)。
- 支持小写,去重,排序,移除停用词,以及
Character filter
- HTML Strip Char Filter
- 处理HTML的,把
<p>I'm so <b>happy</b>!</p>
—>I'm, so, happy
- 处理HTML的,把
- Mapping Character Filter
- 看上面自定义分析器的例子
- Pattern Replace Character Filter
- 用正则表达式进行替换,可能很慢
Tokenizer
分词器分为三大类:面向单词的,面向单词内的,面向结构型文本的。
Word Oriented Tokenizers
- Standard Tokenizer
- 用
Unicode Text Segmentation algorithm
去分隔字符,官方说它是最佳之选。
- 用
- Letter Tokenizer
- 遇到不是字母的就分隔
- Lowercase Tokenizer
- 比letter tokenizer 多了转小写
- Whtespace Tokenizer
- 遇到空格就分隔
- UAX URL Email Tokenizer
- 把URL和Email地址当成一个token
- Classic Tokenizer
- 针对英语语法的分词器
- Thai Tokenizer
- 泰语分词(那么多语言,ES居然专门把泰语分词器列出来,why)
Partial Word Tokenizers
- N-Gram Tokenizer
- 默认使用2-gram,
quick
—>[qu, ui, ic, ck]
- 默认使用2-gram,
- Edge N-gram Tokenizer
- 在单词头设置anchor,如果5-gram的话,
quick
—>[q, qu, qui, quic, quick]
- 在单词头设置anchor,如果5-gram的话,
Structured Text Tokenizers
- Keyword Tokenizer
- 啥也不干
- Pattern Tokenizer
- 正则
- Simple Pattern Tokenizer
- 支持简单的正则,更快,返回匹配的项
- Char Group Tokenizer
- 设置一组字符进行分隔,比正则快
- Simple Pattern Split Tokenizer
- 遇到正则匹配的项就分隔,和上面那个的区别跑一下下面的例子就明白了
- Path_hierarchy Tokenizer
- 根据路径分隔,
/one/two/three
—>[ /one, /one/two, /one/two/three ]
- 根据路径分隔,
1POST _analyze
2{
3 "tokenizer": {
4 "type": "simple_pattern_split",
5 "pattern": "[0123456789]{3}"
6 },
7 "text": "fd-786-335-514-x"
8}
9
10POST _analyze
11{
12 "tokenizer": {
13 "type": "simple_pattern",
14 "pattern": "[0123456789]{3}"
15 },
16 "text": "fd-786-335-514-x"
17}
Token filter
太多了,常用的有:
- ASCII folding token filter
- 把一些拉丁字母转成ASCII字符
- Lowercase token filter
- 转小写
- Length token filter
- 移除长度超过设定值的,可以设置最小或者最大。
- Truncate token filter
- 超过设定长度的就截短
- Stop token filter
- 移除停用词
EPICS PV
直接上代码,添加了epics_pv_analyzer
,并在PVNAME
这个field上使用,在mapping里设置了几个常见的EPICS PV field的映射。把PVTYPE
设置为keyword
就可以做聚合了,看看哪种类型的PV最多(好像没什么用)。
1PUT linac-epics-pv
2{
3 "settings": {
4 "number_of_shards": 1,
5 "number_of_replicas": 0,
6 "analysis": {
7 "analyzer": {
8 "epics_pv_analyzer": {
9 "type": "custom",
10 "tokenizer": "pv_tokenizer",
11 "filter": [
12 "lowercase"
13 ]
14 }
15 },
16 "tokenizer": {
17 "pv_tokenizer": {
18 "type": "char_group",
19 "tokenize_on_chars": [
20 ":",
21 "-",
22 "_",
23 " "
24 ]
25 }
26 }
27 }
28 },
29 "mappings": {
30 "properties": {
31 "PVNAME": {
32 "type": "text",
33 "analyzer": "epics_pv_analyzer",
34 "search_analyzer": "epics_pv_analyzer"
35 },
36 "PVTYPE": {
37 "type": "keyword",
38 "ignore_above": 256
39 },
40 "DTYP": {
41 "type": "text"
42 },
43 "NELM": {
44 "type": "integer"
45 },
46 "PINI": {
47 "type": "keyword"
48 },
49 "FLNK": {
50 "type": "text",
51 "analyzer": "epics_pv_analyzer",
52 "search_analyzer": "epics_pv_analyzer"
53 },
54 "FTVL": {
55 "type": "keyword"
56 }
57 }
58 }
59}
60# 测试分析器
61POST linac-epics-pv/_analyze
62{
63 "analyzer": "epics_pv_analyzer",
64 "text": "LIiBM:SP_61_F5_1:Y1PK:ZRE:1S:INP"
65}
66# 修改mapping
67PUT linac-epics-pv/_mapping
68{
69 "properties": {
70 "PVNAME": {
71 "type": "text",
72 "analyzer": "epics_pv_analyzer",
73 "search_analyzer": "epics_pv_analyzer"
74 },
75 "PVTYPE": {
76 "type": "keyword",
77 "ignore_above": 256
78 },
79 "DTYP": {
80 "type": "text",
81 },
82 "NELM": {
83 "type": "integer",
84 },
85 "PINI": {
86 "type": "keyword",
87 },
88 "FLNK": {
89 "type": "text",
90 "analyzer": "epics_pv_analyzer",
91 "search_analyzer": "epics_pv_analyzer"
92 },
93 "FTVL": {
94 "type": "keyword",
95 },
96 }
97}
98# 搜索
99GET linac-epics-pv/_search
100{
101 "size": 20,
102 "query": {
103 "match": {
104 "PVNAME": {
105 "query": "liibm zre inp",
106 "operator": "and"
107 }
108 }
109 }
110}