草庐IT

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

国服亚瑟 2023-12-30 原文

Elasticsearch 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
}

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

这条语句是查询不到的
GET /pigg_user/_search
{
  "query": {
    "term": {
      "name": "冬哥"
    }
  }
}

(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下面会讲
            }
          }
        }
      }
    }
  }
}

(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": "冬"
    }
  }
}

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": "冬哥"
    }
  }
}

三、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
      }
    }
  }
}

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"
}

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

POST logs-debug/_doc
{
  "date": "2019-12-12",
  "message": "Starting up Elasticsearch",
  "level": "error"
}

返回如下错误提示:

"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]"
}

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"
      }
    }
  }
}

有关【Elasticsearch教程8】Mapping字段类型之keyword的更多相关文章

  1. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  2. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  3. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  4. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  5. ruby-on-rails - 在 Rails 和 ActiveRecord 中查询时忽略某些字段 - 2

    我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr

  6. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  7. ruby - 查找字符串中的内容类型(数字、日期、时间、字符串等) - 2

    我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s

  8. ruby-on-rails - 在 Rails 开发环境中为 .ogv 文件设置 Mime 类型 - 2

    我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain

  9. postman接口测试工具-基础使用教程 - 2

    1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,

  10. 在VMware16虚拟机安装Ubuntu详细教程 - 2

    在VMware16.2.4安装Ubuntu一、安装VMware1.打开VMwareWorkstationPro官网,点击即可进入。2.进入后向下滑动找到Workstation16ProforWindows,点击立即下载。3.下载完成,文件大小615MB,如下图:4.鼠标右击,以管理员身份运行。5.点击下一步6.勾选条款,点击下一步7.先勾选,再点击下一步8.去掉勾选,点击下一步9.点击下一步10.点击安装11.点击许可证12.在百度上搜索VM16许可证,复制填入,然后点击输入即可,亲测有效。13.点击完成14.重启系统,点击是15.双击VMwareWorkstationPro图标,进入虚拟机主

随机推荐