Analysis
Analysis 解析器由三个模块=character filters(字符过滤器), tokenizers(标记器), and token filters(标记过滤器)组成
Analysis 中的自定义分词
analysis 基本概念 === 全文索引中会用到Tokenizer
(分词器)对文档分词,提取token
(词元),讲token进一步处理如大小写转换的算法叫Filter
(过滤器)。
所以当提供的分词器不满足我们使用时,比如中文分词,我们需要自定义分词
自定义分词结构如下
正常来说,我们可以在mapping中创建索引时设置
analyzer
指定,但是对于更多的分词需求就要自定义
分词来达到想要的效果
需求:需要对中文分词,同义词转换,特殊字符过滤,html过滤
PUT /test
{
"settings": {
"analysis": {
"analyzer":{//自定义分词
"my_test_analyzer":{
"type":"custom", //自定义类型
"tokenizer": "ik_smart", //分词器
"filter":["lowercase","my_synonym"],//使用带配置
"char_filter":["mapping_filter","html_filter"] //使用带配置
}
},
"char_filter": {
"html_filter":{
"type":"html_strip"
},
"mapping_filter":{
"type":"mapping",
"mappings": [
"yi=>一",//需要转换的字符
"er=>二",
"Π=>n"
]
}
},
"filter": {
"my_synonym":{//同义词
"type":"synonym",
"synonyms":[
"工商,工行=>中国工商银行",
"农行=>中国农业银行"
]
}
}
}
}
}
看下分词结果
GET test/_analyze
{
"text": ["<p>我们在工行?Whats YOU Πame</p>"],
"analyzer": "my_test_analyzer"
}
常用分词配置
https://www.elastic.co/guide/en/elasticsearch/reference/7.16/analysis.html
Tokenizers(分词器)
letter 非字母时分割文本
GET _analyze
{
"text": "你是谁 阿克苏德拉科时间到了",
"tokenizer": "letter"
}
lowercase 非字母分割+转为小写
# lowercase 非字母时分割文本+元转为小写
GET _analyze
{
"text": "WHO Are You1so",
"tokenizer": "lowercase"
}
whitespace 空格分割文本
GET _analyze
{
"text": "WHO You,你 是谁",
"tokenizer": "whitespace"
}
###uax_url_email URL ,email 词元
GET _analyze
{
"text": "http://localhost:8080/api是:111111111@163.com",
"tokenizer": "uax_url_email"
}
char_group 自定义标记语法
POST _analyze
{
"tokenizer": {
"type": "char_group",
"tokenize_on_chars": [
"whitespace",//空格
"-"//自定义
]
},
"text": "我的Email 是-111111111@163.com"
}
- letter —单词 for example a, b, ï or 京
- digit — 数字for example 3 or 7
- whitespace — 空格 for example " " or “\n”
- punctuation — 标点符号 for example ! or "
-symbol — 符号 for example $ or √
edge_ngram 从词语的最左侧逐一分词
POST _analyze
{
"tokenizer": {
"type": "edge_ngram",
"min_gram": 2,//最小长度
"max_gram": 6,//最大长度
"token_chars":[//应包含在词元中的字符类。es将分割不属于指定类的字符 []为全部
"letter",//对单词分词
"digit"//对数字分词
]
},
"text": "这是中文123456789"
}
N-grams 是一个连续的指定长度的字符序列
max_gram和min_gram的差值必须小于或等于:[1]
POST _analyze
{
"tokenizer": {
"type": "ngram",
"min_gram": 3,//连续最小词数量
"max_gram": 4,//连续最大词数量
"token_chars":[//处理词的范围
"letter",
"digit",
"whitespace"
]
},
"text": "是中文1234 驱蚊器"
}
path_hierarchy路径层次分词
POST _analyze
{
"tokenizer": {
"type": "path_hierarchy",
"skip":0,//忽视初始词量 就是删除前n个分词 默认0
"delimiter":"/",//分隔符 默认/
"replacement":"#" ,//路径分隔符替换 默认是delimiter
"reverse":false//以相反的顺序发射词元。默认是 false 。
},
"text": "/usr/local/tomcat"
}
keyword 整词
POST _analyze
{
"analyzer": "keyword",
"text": "你猜我是谁"
}
Token Filters(词元过滤器)
Apostrophe (撇号/单引号过滤器)
中文不生效
GET /_analyze
{
"tokenizer" : "standard",
"filter" : ["apostrophe"],
"text" : "it's"
}
Keep Types (保留指定类型过滤器)
GET _analyze
{
"tokenizer": "standard",
"filter": [
{
"type": "keep_types",
"types": [ "<NUM>" ]
}
],
"text": "2012年12月12"
}
- 字母
- 韩语
- 数字
keep (保留字过滤器)
GET _analyze
{
"tokenizer": "ik_smart",
"filter": [
{
"type": "keep",
"keep_words": [ "一只","我","一只量"]
}
],
"text": "我是一只量"
}
stop停词
英文分词中有指定的停词,IK中文分词内也有指定停词
GET /_analyze
{
"tokenizer": "ik_smart",
"filter": [
{
"type": "stop",
"stopwords": [ "一只","我","一只量"]
}
],
"text": "我是一只量"
}
trim去除左右空格
GET _analyze
{
"tokenizer" : "keyword",
"filter" : ["trim"],
"text" : " 你好 呀"
}
Character Filters(字符过滤器)
html_strip 过滤
POST _analyze
{
"tokenizer": "keyword",
"char_filter":{
"type":"html_strip",
"escaped_tags":["b"]//排除标签
},
"text": "<p>这是P标签<b>happy</b>!</p>"
}
mapping 字符过滤转换
GET /_analyze
{
"tokenizer": "keyword",
"char_filter": [
{
"type": "mapping",
"mappings": [
"yi=>一",//需要转换的字符
"er=>二",
"san=>三"
]
}
],
"text": "跟我说yiersan"
}
IK分词器+热更新
请看我另一篇文章
https://blog.csdn.net/crazyo2jam/article/details/107894090
拼音分词
https://github.com/medcl/elasticsearch-analysis-pinyin
分词设置说明
keep_first_letter : 刘德华>ldh, 默认: true
keep_separate_first_letter: 刘德华>l,d,h, 默认: false,由于词条太频繁,查询结果可能太模糊
limit_first_letter_length:设置第一个_字母结果的最大长度,默认值:16
keep_full_pinyin : 刘德华> [liu,de,hua], 默认: true
keep_joined_full_pinyin : 刘德华> [liudehua], 默认: false
keep_none_chinese:在结果中保留非中文字母或数字,默认值:true
keep_none_chinese_together将非中文字母保持在一起,默认值:true,例如:DJ音乐家->DJ,yin,yue,jia,当设置为false时,例如:DJ音乐家->D,J,yin,yue,jia,注意:keep_none_chinese应该首先启用
keep_none_chinese_in_first_letter在第一个字母中保留非中文字母 : 刘德华AT2016->ldhat2016, 默认: true
==keep_none_chinese_in_joined_full_pinyin == 将非中文字母保留在拼音拼音中 刘德华2016->liudehua2016, 默认: false
none_chinese_pinyin_tokenize 如果非中文字母是拼音,则将其拆分成单独的拼音项,默认值为true,例如:liudehuaalibaba13zhuanhan->liu,de,hua,a,li,ba,ba,13,zhuang,han,注意:keep_none_chinese和keep_none_chinese_组合在一起应该首先启用
keep_original 保持原始当此选项启用时,也将保持原始输入,默认值:false
lowercase 小写小写非中文字母,默认为true
trim_whitespace default: true
remove_duplicated_term 启用此选项后,将删除重复的术语以保存索引,例如:de的>de,默认值:false,注意:位置相关的查询可能会受到影响
ignore_pinyin_offset 6.0以后,对偏移量有严格的约束,不允许重叠令牌,有了这个参数,忽略偏移量将允许重叠令牌,请注意,所有与位置相关的查询或高亮显示都将不正确,您应该使用多个字段,并针对不同的查询目的指定不同的设置。如果需要偏移,请将其设置为false。默认值:true。
DELETE my_index
PUT my_index
{
"settings": {
"analysis": {
"analyzer": {
"ik_pinyin_analyzer": {
"type": "custom",
"tokenizer": "ik_smart",
"char_filter": ["emoticons"],
"filter":["lowercase","my_stop","my_pinyin", "word_delimiter"]
},
"ik_smart_synonym_analyzer": {
"type": "custom",
"tokenizer": "ik_smart",
"char_filter": ["emoticons"],
"filter": ["lowercase","my_stop","my_synonym_filter"]
},
"ik_max_word_synonym_analyzer": {
"type": "custom",
"tokenizer": "ik_max_word",
"char_filter": ["emoticons"],
"filter": ["lowercase","my_stop","my_synonym_filter"]
}
},
"char_filter": {
"emoticons": {
"type": "mapping",
"mappings": [
"一 => 衣",
":( => _sad_"
]
}
},
"filter":{
"my_pinyin":{
"type" : "pinyin",
"keep_separate_first_letter" : false,
"keep_joined_full_pinyin": true,
"keep_original" : true,
"limit_first_letter_length" : 16,
"lowercase" : true,
"remove_duplicated_term" : true
},
"my_stop": {
"type": "stop",
"stopwords": "的"
},
"my_synonym_filter": {
"type": "synonym",
"synonyms_path": "analysis/synonyms.txt"
}
}
}
},
"mappings": {
"properties" : {
"context" : {
"type" : "text",
"analyzer" : "ik_smart_synonym_analyzer",
"fields": {
"pinyin": {
"type": "text",
"term_vector": "with_positions_offsets",
"analyzer": "ik_pinyin_analyzer",
"boost": 10
}
}
}
}
}
}
POST my_index/_doc/1
{
"context":"我爱祖国"
}
POST my_index/_doc/2
{
"context":"我是程序员"
}
GET my_index/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"context": "程序员"
}
}
]
}
}
}
GET my_index/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"context.pinyin": "chengxvyuan"
}
}
]
}
}
}
说明
"analysis": { ##分词设置
"analyzer": { ##自定义分词器
"ik_pinyin_analyzer": { ##分词器名子
"type": "custom", ##类型 custom为自定义
"tokenizer": "ik_smart", ##分词器 IK
"char_filter": ["emoticons"], ##特殊字符转换
"filter":["lowercase","my_stop","my_pinyin", "word_delimiter"]
##使用的过滤器 (其实就是我们配置的分词种类)
},
},
"char_filter": { ##字符转换
"emoticons": {
"type": "mapping",
"mappings": [
"一 => 衣",
":( => _sad_"
]
}
},
"filter":{ ##过滤器设置
"my_pinyin":{ ##名字 下面是过滤器设置 这个是看官网的api写
"type" : "pinyin",
"keep_separate_first_letter" : false,
"keep_joined_full_pinyin": true,
"keep_original" : true,
"limit_first_letter_length" : 16,
"lowercase" : true,
"remove_duplicated_term" : true
},
"my_stop": { ##停词 不过IK已经带停词词典了
"type": "stop",
"stopwords": "的"
},
"my_synonym_filter": { ##同义词设置
"type": "synonym",
"synonyms_path": "analysis/synonyms.txt" ##路径必须在es在的conf内
}
}
}
我测试的是IK+同义+拼音的组合是有问题的
所以我们把同义和拼音分开 mapping中通过
"fields": {
"pinyin": {
"type": "text",
"term_vector": "with_positions_offsets",
"analyzer": "ik_pinyin_analyzer",
"boost": 10
}
}
通过字段.pinyin使用拼音分词
另外 设置拼音分词的时候不可以设置 search_analyzer
这样子会导致我们使用拼音分词时必须字与字之间有分隔才可以识别
比如 liudehua 是搜不出来的 liu de hua 是可以的
应该是分词的问题导致