【Elastic Engineering】Elasticsearch:理解 mapping 中的 null_value

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: Elasticsearch:理解 mapping 中的 null_value

作者:刘晓国


null 不能被索引或搜索。 当字段设置为 null(或空数组或 所有值为 null 值的数组)时,将其视为该字段没有值。使用 null_value 参数可以用指定的值替换显式的空值,以便可以对其进行索引和搜索。


例子一

PUT my-index-000001
{
  "mappings": {
    "properties": {
      "status_code": {
        "type":       "keyword",
        "null_value": "NULL" 
      }
    }
  }
}

在上面,我们针对 status_code 字段定义其 null_value,也就是说当我们导入一个文档,当它的 status_code 指定为 null 时,那么在导入时,实际上它是被认为是 status_code 当做 "NULL" 被导入并进行分析。我们以下面的两个文档来进行说明:

PUT my-index-000001/_doc/1
{
  "status_code": null
}
PUT my-index-000001/_doc/2
{
  "status_code": [] 
}

使用上面的两个命令写入两个文档到索引 my-index-000001 中。我们执行如下的搜索:

GET my-index-000001/_search

我们可以搜索到两个文档:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "my-index-000001",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "status_code" : null
        }
      },
      {
        "_index" : "my-index-000001",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "status_code" : [ ]
        }
      }
    ]
  }
}

这显然是正确的,因为我们导入了两个文档。我们接着进行如下的搜索:

GET my-index-000001/_search
{
  "query": {
    "term": {
      "status_code": "NULL" 
    }
  }
}

上面的命令显示的结果为:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "my-index-000001",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.2876821,
        "_source" : {
          "status_code" : null
        }
      }
    ]
  }
}

显然,第一个文档被搜索到,而第二个文档没有被搜索到。这是因为在第一个文档中,它清楚地指出 "status_code": null,所以在导入文档时,null_value 被认为是 status_code 而被导入并进行分析。第二个文档没有指定它是 null,所以没有被搜索出来。


例子二


假如我们有一下两个文档:

PUT twitter/_doc/1
{
  "age": null
}
PUT twitter/_doc/2
{
  "age": 20
}

在上面,我们有两个文档。第一个文档的 age 值为 null,也就是说它不能被搜索到。假如我们做如下的聚合:

GET twitter/_search
{
  "size": 0,
  "aggs": {
    "avg_age": {
      "avg": {
        "field": "age"
      }
    }
  }
}

那么上面的聚合返回:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "avg_age" : {
      "value" : 20.0
    }
  }
}

也就是说平均年龄是 20 岁,这是因为第一个文档被视为不见。我们怎么才能让第一个文档也参入聚合呢?我们可以使用 null_value 来为 null 值的字段设置一个值。我们修改 mapping 为:

DELETE  twitter
PUT twitter
{
  "mappings": {
    "properties": {
      "age": {
        "type": "float",
        "null_value": 0
      }
    }
  }
}

我们再重新导入之前的两个文档:

PUT twitter/_doc/1
{
  "age": null
}
PUT twitter/_doc/2
{
  "age": 20
}

由于我们已经定义当 age 为 null 时,null_value 将会起作用,它的值将为 0,那么这个文档将为可见。执行如下的聚合:

GET twitter/_search
{
  "size": 0,
  "aggs": {
    "avg_age": {
      "avg": {
        "field": "age"
      }
    }
  }
}

上面的结果为:

{
  "took" : 703,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "avg_age" : {
      "value" : 10.0
    }
  }
}

现在的平均值变为 10 了,也就是 (20 + 0)/2 = 10。


这里必须注意的是,我们必须显示地指定 age 为 null,否则 null_vale 将不会起任何的作用。比如:

DELETE twitter
PUT twitter
{
  "mappings": {
    "properties": {
      "age": {
        "type": "float",
        "null_value": 0
      }
    }
  }
}
PUT twitter/_doc/1
{
  "content": "This is cool"
}
PUT twitter/_doc/2
{
  "age": 20,
  "content": "This is cool too!"
}

在上面,第一个文档里没有定义 age,那么 null_value 将不会起作用。如果我们做如下的聚合:

GET twitter/_search
{
  "size": 0,
  "aggs": {
    "avg_age": {
      "avg": {
        "field": "age"
      }
    }
  }
}

其显示结果为:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "avg_age" : {
      "value" : 20.0
    }
  }
}

也就是说第一个文档没有被搜索到。


相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
3月前
|
JSON 自然语言处理 定位技术
Elasticsearch Mapping是啥?
Elasticsearch Mapping是啥?
74 0
|
8月前
|
存储 JSON 自然语言处理
【Elasticsearch】学好Elasticsearch系列-Mapping
【Elasticsearch】学好Elasticsearch系列-Mapping
85 0
|
9月前
|
JSON 自然语言处理 定位技术
Elasticsearch Mapping是啥?
Elasticsearch Mapping是啥?
85 0
|
存储 JSON 自然语言处理
Elasticsearch7.X Mapping 常见字段类型整理
一、核心数据类型 字符串:text, keyword 数值型:long, integer, short, byte, double, float, half_float, scaled_float 布尔型:boolean 日期型:date, date_nanos 二进制:binary
|
JSON Java API
Elasticsearch Dynamic Mapping(动态映射机制)
Elasticsearch Dynamic Mapping(动态映射机制)
Elasticsearch Dynamic Mapping(动态映射机制)
|
存储 JSON 自然语言处理
Elasticsearch Mapping之字段类型(field datatypes)
Elasticsearch Mapping之字段类型(field datatypes)
Elasticsearch Mapping之字段类型(field datatypes)
|
存储 JSON 自然语言处理
Elasticsearch Mapping parameters(主要参数一览)
Elasticsearch Mapping parameters(主要参数一览)
Elasticsearch Mapping parameters(主要参数一览)
|
存储 JSON 关系型数据库
Elasticsearch Mapping类型映射概述与元字段详解
Elasticsearch Mapping类型映射概述与元字段详解
Elasticsearch Mapping类型映射概述与元字段详解
|
存储 索引
|
JSON 自然语言处理 数据库

相关产品

  • 检索分析服务 Elasticsearch版