• 【Elasticsearch教程8】Mapping字段类型之keyword


    一、前言

    ES的keyword类型家族有3种:

    1. keyword,用于结构化内容,如ID、邮箱、邮编、手机号、主机名、状态码或标记
    2. constant_keyword,某个字段为constant_keyword类型,则该index中,所有文档的该字段的值必须一致
    3. wildcard,存非机构化数据,且值的内容大,相似性低的数据,如HTTP请求体,Log日志这些让人阅读性差的数据。

    其中第1个keyword类型是最常用的类型,后面2个类型出现的比较晚,使用的场景也比较少。

    二、keyword

    2.1 keyword适用场景

    keyword类型通常存储结构化数据,对keyword类型不能进行match查询,适合用keyword的例子:

    场景
    订单状态1:未付款;2:已付款;3:申请退款;4:已退款
    HTTP状态码200,400,500,404
    ID/手机号/邮箱/性别对手机号没必要分词,也不需要数学计算,所以也不能设为数字类型
    用户画像标签学生,IT男,腐女,宝妈
    • ES把keyword类型的值作为一整体存在倒排索引中,不进行分词。
    • keyword适合存结构化数据,如性别、手机号、数据状态、标签HttpCode(404,200,500)等。
    • 字段常用来精确查询、过滤、排序、聚合时,应设为keyword,而不是数值型。
    • 如果某个字段你经常用来做range查询, 你还是设置为数值型(integer,long),ES对数字的range有优化。
    • 还可以把字段设为multi-field,这样又有keyword类型又有数值类型,方便多种方式的使用。
    • 最长支持32766个UTF-8类型的字符,但放入倒排索引时,只截取前一段字符串,长度由ignore_above参数决定,默认"ignore_above" : 256

    2.2 keyword实验

    (1)创建一个文档

    PUT /pigg_user/_doc/1
    {
      "name": "冬哥",
      "age": 32
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    (2)查询name="冬哥"的数据,用termname字段上查询,是查询不到文档的

    这条语句是查询不到的
    GET /pigg_user/_search
    {
      "query": {
        "term": {
          "name": "冬哥"
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    (3)查看文档的mapping
    要想探知没有搜到的原因,得先看排查文档的mapping,发现name是text类型,其下面有一个keyword子类型

    GET /pigg_user/_mapping
    
    #返回如下
    {
      "pigg_user" : {
        "mappings" : {
          "properties" : {
            "age" : {
              "type" : "long"
            },
            "name" : {
              "type" : "text",
              "fields" : {
                "keyword" : {          #这行的keyword是字段名,全称是name.keyword
                  "type" : "keyword",  #这行的keyword是指类型
                  "ignore_above" : 256 #这里的ignore_above下面会讲
                }
              }
            }
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    (4)分析原因
    如果不设置mapping,ES默认把字符串设为text类型,并包含一个keyword子类型
    name是text类型,“冬哥”这个词已经被拆成“冬”和“哥”这2个词。
    所以上面用term来匹配“冬哥”时,查询不到数据。
    简单理解:

    • “name”这个字段按照“冬”和“哥”2个词存的,根据“冬”或者“哥”都能term查询到文档。
    • “name.keyword”这个字段存储的是“冬哥”这完整字符串。
    #根据name匹配“冬”,可以查询到文档
    GET /pigg_user/_search
    {
      "query": {
        "term": {
          "name": "冬"
        }
      }
    }
    
    #根据name.keyword匹配"冬哥",可以查询到文档
    GET /pigg_user/_search
    {
      "query": {
        "term": {
          "name.keyword": "冬哥"
        }
      }
    }
    
    #根据name.keyword匹配"冬",查询不到文档
    GET /pigg_user/_search
    {
      "query": {
        "term": {
          "name.keyword": "冬"
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    2.3 手动设置keyword类型

    #先删除之前创建的index
    DELETE pigg_user
    
    #设置name为keyword,age为short。
    PUT pigg_user
    {
      "mappings": {
        "properties": {
          "name": {
            "type":  "keyword"
          },
          "age": {
            "type": "short"
          }
        }
      }
    }
    
    #新增一个文档
    PUT /pigg_user/_doc/1
    {
      "name": "冬哥",
      "age": 32
    }
    
    #根据name精确匹配,可以查到数据
    GET /pigg_user/_search
    {
      "query": {
        "term": {
          "name": "冬哥"
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    三、constant_keyword类型

    constant_keyword keyword 字段的特例,用于索引中所有文档具有相同值的情况。

    PUT logs-debug
    {
      "mappings": {
        "properties": {
          "@timestamp": {
            "type": "date"
          },
          "message": {
            "type": "text"
          },
          "level": {
            "type": "constant_keyword", #指明level这个字段是constant_keyword类型
            "value": "debug"           	#且所有文档的level字段的值都是debug
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    constant_keyword 支持与 keyword 字段相同的查询和聚合,而且constant_keyword的效率更高,因为ES利用所有文档的的某个constant_keyword字段的值必须相同的这一事实,进行了针对性优化。

    允许提交没有字段值值等于映射中配置的值的文档。 以下两个索引请求是等效的:

    POST logs-debug/_doc
    {
      "date": "2019-12-12",
      "message": "Starting up Elasticsearch",
      "level": "debug"
    }
    
    POST logs-debug/_doc
    {
      "date": "2019-12-12",
      "message": "Starting up Elasticsearch"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    如果把level设置成非debug的值,比如error,则会返回错误

    POST logs-debug/_doc
    {
      "date": "2019-12-12",
      "message": "Starting up Elasticsearch",
      "level": "error"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    返回如下错误提示:

    "caused_by" : {
      "type" : "illegal_argument_exception",
      "reason" : "[constant_keyword] field [level] only accepts values that are equal to the value defined in the mappings [debug], but got [error]"
    }
    
    • 1
    • 2
    • 3
    • 4

    constant_keyword类型使用的场景确实非常少见,所以用的很少。

    四、wildcard类型

    当你要在某个非结构化数据上进行wildcardregexp查询的时候,wildcard类型就比较合适了。

    • 这种非结构化数据的内容一般是机器产生的(machine-generated),它们的可阅读比较低,不适合我们人阅读,比如日志message或者HTTP的请求体。
    PUT my-index-000001
    {
      "mappings": {
        "properties": {
          "my_wildcard": {
            "type": "wildcard"
          }
        }
      }
    }
    
    PUT my-index-000001/_doc/1
    {
      "my_wildcard" : "This string can be quite lengthy"
    }
    
    GET my-index-000001/_search
    {
      "query": {
        "wildcard": {
          "my_wildcard": {
            "value": "*quite*lengthy"
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
  • 相关阅读:
    python采集天气数据 并做数据可视化 (含完整源代码)
    【EAI 026】RoboGen: 通过自动数据生成管线实现机器人技能学习
    routeDone with a webviewId 26 that is not the current page在uniapp运行过程中出现的报错
    【游戏建模全流程】使用ZBrush制作龙模型
    OpenGL入门(二)之渲染管线pipeline,着色器Shader
    Python文件操作详细介绍(打开、读取、写入、上下文管理器、关闭、异常处理;文件模式、编码、路径、读写位置、复制、移动、删除)
    .NET混合开发解决方案7 WinForm程序中通过NuGet管理器引用集成WebView2控件
    站在自动装配角度浅析Spring和SpringBoot的区别
    2022 Nomachine 最简安装与使用指南
    熬夜整理的vue面试题
  • 原文地址:https://blog.csdn.net/winterking3/article/details/126548603