大数据利器Elasticsearch之exists查询

2,129 阅读2分钟

这是我参与8月更文挑战的第17天,活动详情查看:8月更文挑战
本Elasticsearch相关文章的版本为:7.4.2

exists查询:返回所查询的字段包含具有索引值的文档。

不存在索引值的情况

字段不存在索引值的情况有以下几种:

  1. 字段的源json值为null或[];
  2. 字段的值的长度超过了ignore_above所设置的值;
  3. 字段的值有问题,但是设置了ignore_malformed, 这个字段的值会被丢弃或不进行索引。

测试数据:

PUT /exists_test
{
  "mappings": {
    "properties": {
      "name": {
        "type": "keyword",
        "index": true,
        "ignore_above": 3
      },
      "age": {
        "type": "long",
        "index": true,
        "ignore_malformed": true
      }
    }
  }
}

POST /exists_test/_doc/1
{
  "name": "beijing",
  "age": "xx"
}

POST /exists_test/_doc/2
{
  "name": "",
  "age": 5
}

POST /exists_test/_doc/3
{
  "name": [],
  "age": 5
}

POST /exists_test/_doc/4
{
  "name": null,
  "age": 5
}

测试null和ignore_above

校验当字段的源json值为null或[]时以及字段的值的长度超过了ignore_above所设置的值,那么exists查询这个字段时不会返回文档。

GET /exists_test/_search
{
  "query":{
    "exists": {
      "field": "name"
    }
  }
}

返回结果: 因为doc1的name的值长度大于3,所以不会进行倒排索引,所以exists查询没有命中;doc3和doc4的值为null和[], 所以exists查询这个字段时也不会返回文档。

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "exists_test",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "name" : "",
          "age" : 5
        }
      }
    ]
  }
}

测试数据类型错误时

校验字段的值有问题,但是设置了ignore_malformed, 这个字段的值会不进行索引。

GET /exists_test/_search
{
  "query":{
    "exists": {
      "field": "age"
    }
  }
}

返回结果: 因为文档1的age的值为字符串"xx" , 但是age的数据类型在mapping中是long整数,所以数据类型不对,但是设置了ignore_malformed, 这个字段的值不进行索引。所以exists查询就不会返回doc1。

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "exists_test",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "name" : "",
          "age" : 5
        }
      },
      {
        "_index" : "exists_test",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "name" : [ ],
          "age" : 5
        }
      },
      {
        "_index" : "exists_test",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 1.0,
        "_source" : {
          "name" : null,
          "age" : 5
        }
      }
    ]
  }
}

注意: 属于有值的几种特殊情况:

  • 字符串空串"""-";
  • 数组包含null同时包含另外的有值的数据:[null, "test"]
  • 在mapping里定义的自定义的null-value

获取缺失索引值的文档的方法

当要获取缺失索引值的文档时,可以结合使用must_not的boolean查询和exists查询实现。

GET /exists_test/_search
{
  "query": {
    "bool": {
      "must_not": [
        {"exists": {"field":"age"}}
      ]
    }
  }
}

查询age字段不存在索引值的文档:
因为文档2,3,4的age的值为5,所以它们是存在索引值的。但是文档1的age的值是字符串"xx",不是一个合法的long整数,不存在索引值。所以下面的查询只返回了文档1。

返回的结果:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.0,
    "hits" : [
      {
        "_index" : "exists_test",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.0,
        "_ignored" : [
          "age"
        ],
        "_source" : {
          "name" : "beijing",
          "age" : "xx"
        }
      }
    ]
  }
}