ES - 修改分词器及定制分词器

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ES - 修改分词器及定制分词器相关的知识,希望对你有一定的参考价值。

参考技术A

修改分词器设置
启用stardar停用词token filter,在stardard中stop token filter是默认被禁用的

定制化自己的分词器

在指定的type里面用定制化的分词器

ELK专栏之ES索引-04

ELK专栏之ES索引-04


索引Index入门

为什么我们要手动创建索引?

● 在生产上,我们需要自己手动建立索引和映射,是为了更好的管理索引,就像数据库的建表数据一样。


索引管理

创建索引

● 创建索引的语法:

PUT /index

    "settings":...,
    "mappings":
        "properties":
            ...
        
    ,
    "aliases":
        "default_index":
               

示例:

● 创建索引:

PUT /my_index

  "settings": 
    "number_of_shards": 1,
    "number_of_replicas": 1
  ,
  "mappings": 
    "properties": 
      "field1":
        "type": "text"
      ,
      "field2":
        "type": "text"
      
    
  ,
  "aliases": 
    "default_index": 
  

插入数据:

PUT /my_index/_doc/1

	"field1":"java",
	"field2":"js"

查询数据:

GET /my_index/_doc/1
GET /default_index/_doc/1

查询索引

语法:查询索引:

GET /index

语法:查询索引中的映射信息

GET /index/_mapping

示例:

GET /my_index
GET /my_index/_mapping
GET /my_index/_settings

修改索引

语法:

PUT /index/_settings

    "index" : 
        "number_of_replicas" : 5
    

示例:修改副本分片数

PUT /my_index/_settings

    "index" : 
        "number_of_replicas" : 5
    


删除索引

语法:删除索引

DELETE /index

语法:删除多个索引

DELETE /index1,index2
DELETE /index*

语法:删除全部索引(危险)

DELETE /_all

示例:删除索引

DELETE /book

示例:删除多个索引

DELETE /book,my_index

示例:

DELETE /book*

示例:删除所有索引

DELETE /_all

为了安全起见,防止恶意删除索引,删除的时候必须指定索引名,我们可以在elasticsearch.yml中配置action.destructive_requires_name: true。


定制分词器

默认分词器

● 分词器有三个组件,分别为:character filter,tokenizer和token filter。

● 默认的分词器是:standard 分词器。

● standard tokenizer:以单词边界进行切分。

● standard token filter:什么都不做。

● lowercase token filter:将所有字母都转换为小写。

● stop token filter(默认被禁用):移除停用词,比如a、the、it等等。


修改分词器的位置

● 启用english停用词token filter:

PUT /my_index

  "settings": 
    "analysis": 
      "analyzer": 
        "es_std":
          "type":"standard",
          "stopwords":"_english_"
        
      
    
  

使用标准分词器测试分词:

GET /my_index/_analyze

  "analyzer": "standard", 
  "text": "a dog is in the house"

使用english停用词测试分词:

GET /my_index/_analyze

  "analyzer": "es_std",
  "text":"a dog is in the house"


定制自己的分词器

● 定制自己的分词器:

PUT /my_index

  "settings": 
    "analysis": 
      "char_filter": 
        //&替换为and
        "&_to_and": 
          "type": "mapping",
          "mappings": ["&=> and"]
        
      ,
      "filter": 
        //停用词--遇到这些词语会忽略分词
        "my_stopwords": 
          "type": "stop",
          "stopwords": ["the", "a"]
        
      ,
      "analyzer": 
        //自定义分词器
        "my_analyzer": 
          "type": "custom",
           //字符过滤器
          "char_filter": ["html_strip", "&_to_and"],
          //以单词边界进行切分
          "tokenizer": "standard",
          //再进行过滤
          "filter": ["lowercase", "my_stopwords"]
        
      
    
  

测试自定义分词器:

GET /my_index/_analyze

  "analyzer": "my_analyzer",
  "text": "tom&jerry are a friend in the house, <a>, HAHA!!"


设置字段使用自定义分词器:

PUT /my_index/_mapping/

  "properties": 
    "content": 
      "type": "text",
      "analyzer": "my_analyzer"
    
  


type底层结构及弃用原因

type是什么?

● type是一个Index中用来区分类似的数据的。这些类似的数据,可能有不同的fields,而且有不同的属性来控制索引和分词器的建立。

● field的value,在底层的Lucene中建立索引的时候,全都是opaque bytes类型,是不区分类型的。

● Lucene是没有type的概念的,在document(文档)中,实际上是将type作为document(文档)的field来存储的,即_type,ES通过_type来进行type的过滤和筛选。


ES中不同的type存储机制

● 一个Index中的多个type,实际上是放在一起存储的,因此同一个Index下,不能有多个type重名,因为那样是无法处理的。

● 比如:创建索引:


   "goods": 
      "mappings": 
         "electronic_goods": 
            "properties": 
               "name": 
                  "type": "string",
               ,
               "price": 
                  "type": "double"
               ,
               "service_period": 
                  "type": "string"
                   			
                
         ,
         "fresh_goods": 
            "properties": 
               "name": 
                  "type": "string",
               ,
               "price": 
                  "type": "double"
               ,
               "eat_period": 
              		"type": "string"
               
                
         
      
   

插入数据:

PUT /goods/electronic_goods/1

  "name": "小米空调",
  "price": 1999.0,
  "service_period": "one year"

PUT /goods/fresh_goods/1

  "name": "澳洲龙虾",
  "price": 199.0,
  "eat_period": "one week"

ES文档在底层的存储是这个样子的:


   "goods": 
      "mappings": 
        "_type": 
          "type": "text",
          "index": "false"
        ,
        "name": 
          "type": "text"
        
        "price": 
          "type": "double"
        
        "service_period": 
          "type": "text"
        ,
        "eat_period": 
          "type": "text"
        
      
   

那么插入的数据在底层的数据存储格式:


  "_type": "electronic_goods",
  "name": "小米空调",
  "price": 1999.0,
  "service_period": "one year",
  "eat_period": ""


  "_type": "fresh_goods",
  "name": "澳洲龙虾",
  "price": 199.0,
  "service_period": "",
  "eat_period": "one week"


type弃用的原因

● 同一个索引下,不同type的数据存储其他type的field的大量空值,会造成资源浪费。

● 所以,不同类型的数据,要放在不同的索引中。

● ES9中,将彻底删除type。


定制动态映射(dynamic mapping)

定制动态映射(dynamic mapping)策略

语法:

PUT /index

    "settings": ...,
    "mappings": 
        "dynamic": "xxx",
        "properties": 
            "filed1": 
                "type": ""
            ,
            "filed2": 
                "type": "",
                "dynamic": "xxx"
            ,
            ...
        
    ,
    "aliases": 
        "default_index": 
    

dynamic:

  • true,遇到陌生字段,就进行dynamic mapping,会自动帮助我们创建映射。
  • false:新检测到的字段将被忽略。这些字段将不会被索引,因此将无法搜索,但仍将出现在返回的源字段中。这些字段不会添加到映射中,必须显示的添加新字段。
  • strict:遇到陌生字段,就报错。

● 示例:

● 创建索引

PUT /my_index

    "mappings": 
        "dynamic": "strict",
        "properties": 
            "title": 
                "type": "text"
            ,
            "address": 
                "type": "object",
                "dynamic": "true"
            
        
    

测试插入数据

PUT /my_index/_doc/1

  "title": "my article",
  "content": "this is my article",
  "address": 
    "province": "guangdong",
    "city": "guangzhou"
  


如果是false情况下,content陌生字段不会被索引,我们在进行全局搜索时,不会搜索到content字段,但是如果搜索别的字段,搜索到该条记录时,还是会携带返回content字段的。

查询my_index的底层mapping映射,也可以发现其中并没有为content字段建立映射。

GET /my_index/_mapping

  "my_index" : 
    "mappings" : 
      "dynamic" : "false",
      "properties" : 
        "address" : 
          "dynamic" : "true",
          "properties" : 
            "city" : 
              "type" : "text",
              "fields" : 
                "keyword" : 
                  "type" : "keyword",
                  "ignore_above" : 256
                
              
            ,
            "province" : 
              "type" : "text",
              "fields" : 
                "keyword" : 
                  "type" : "keyword",
                  "ignore_above" : 256
                
              
            
          
        ,
        "title" : 
          "type" : "text"
        
      
    
  


自定义动态映射(dynamic mapping)策略

  • ES会根据传入的值,自动推断类型。

● 日期探测(Date Detection):默认会按照一定格式识别date,比如yyyy-MM-dd,但是如果某个field先过来一个"2019-11-11"的值,就会自动被dynamic mapping识别成date,后面如果在过来一个"hello world"之类的值,就会报错。可以手动关闭某个type的date detection,如果有需要,自己手动指定某个field为date类型。

● 语法:

PUT /index

    "mappings": 
        "date_detection": false,
        "properties": 
            "filed1": 
                "type": ""
            ,
            "filed2": 
                "type": ""
            ,
            ...
        
    

示例:关闭日期探测

PUT /my_index

    "mappings": 
      "date_detection": false,
       "properties": 
        "title": 
          "type": "text"
        ,
        "address": 
          "type": "object",
          "dynamic": "true"
        
	    
    

测试插入数据:

PUT /my_index/_doc/1

  "title": "my article",
  "content": "this is my article",
  "address": 
    "province": "guangdong",
    "city": "guangzhou"
  ,
  "post_date":"2019-09-10"


● 自定义日期格式:dynamic_date_formats可以定制自己的格式。

● 语法:

PUT /index

    "mappings": 
        "dynamic_date_formats": ["MM/dd/yyyy"],
        "properties": 
            "filed1": 
                "type": ""
            ,
            "filed2": 
                "type": ""
            ,
            ...
        
    

示例:自定义日期格式

PUT /my_index

  "mappings": 
    "dynamic_date_formats": ["MM/dd/yyyy"]
  

测试插入数据:

PUT /my_index/_doc/1

  "create_date": "09/25/2019"


● 数字探测(Numeric Detection):虽然JSON支持本机浮点和整数数据类型,但是某些应用程序或语言有时候可能将数字呈现为字符串。通常正确的解决方案是显示的映射这些字段,那么就可以启用数字检测(默认情况下禁用)来自动完成这些操作。

● 语法:

PUT /index

    "mappings": 
        "numeric_detection": true,
        "properties": 
            "filed1": 
                "type": ""
            ,
            "filed2": 
                "type": ""
            ,
            ...
        
    

示例:开启数字探测

PUT /my_index

  "mappings": 
    "numeric_detection": true
  

测试插入数据:

PUT /my_index/_doc/1

  "my_float":   "1.0", 
  "my_integer": "1" 


定义自己的dynamic mapping template(动态映射模板)

● 动态映射模板允许我们自定义映射,这些映射可以应用到动态添加的字段。

● 语法:

PUT index

    "mappings": 
        "dynamic_templates": [
            
                "template_name": 
                    ...  match conditions ...
                    "mapping":  ... 
                
            ,
            ...
        ]
    

  • template_name:模板名称可以是任何字符串。
  • match conditions:匹配条件,包括match_mapping_type、match、match_pattern、unmatch、path_match、path_unmatch。
  • mapping:匹配字段应该使用的映射。

● 示例:

● 定制自己的映射模块:

PUT /my_index

    "mappings": 
            "dynamic_templates": [
                 
                  "en": 
                      "match":              "*_en", 
                      "match_mapping_type": "string",
                      "mapping": 
                          "type":           "text",
                          "analyzer":       "english"
                      
                                  
            
        ]
	

插入数据:

PUT /my_index/_doc/1

  "title": "this is my first article"

PUT /my_index/_doc/2

  "title_en": "this is my first article"

搜索:

GET /my_index/_search?q=article
GET /my_index/_search?q=is

title没有匹配到任何的动态模块,默认就是standard分词器,不会过滤掉停用词,像is会进入到倒排索引,用is来搜索是可以搜索到的。

title_en匹配到了动态模块,就是english分词器,会过滤掉停用词,is这种停用词会被过滤掉,用is来搜索是搜索不到的。


模板写法:

PUT my_index

  "mappings": 
    "dynamic_templates": [
      
        "integers": 
          "match_mapping_type": "long",
          "mapping": 
            "type": "integer"
          
        
      ,
      
        "strings": 
          "match_mapping_type": "string",
          "mapping": 
            "type": "text",
            "fields": 
              "raw": 
                "type":  "keyword",
                "ignore_above": 256
              
            
          
        
      
    ]
  

模板参数:

"match":   "long_*",
"unmatch": "*_text",
"match_mapping_type": "string"ELK专栏之ES索引-04

ElasticSearch 分词器,了解一下

linux安装配置Elasticsearchkibanaik分词器及安装时遇到的问题

《自然语言处理实战入门》 文本检索 ---- 文本查询实例:ElasticSearch 配置ik 分词器及使用

ik分词器热更新原理

ES实战ES分词器介绍