小言_互联网的博客

Elasticsearch:理解 mapping 中的 null_value

325人阅读  评论(0)

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

 

例子一


  
  1. PUT my- index- 000001
  2. {
  3. "mappings": {
  4. "properties": {
  5. "status_code": {
  6. "type": "keyword",
  7. "null_value": "NULL"
  8. }
  9. }
  10. }
  11. }

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


  
  1. PUT my- index- 000001/_doc/ 1
  2. {
  3. "status_code": null
  4. }
  5. PUT my- index- 000001/_doc/ 2
  6. {
  7. "status_code": []
  8. }

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

GET my-index-000001/_search

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


  
  1. {
  2. "took" : 1,
  3. "timed_out" : false,
  4. "_shards" : {
  5. "total" : 1,
  6. "successful" : 1,
  7. "skipped" : 0,
  8. "failed" : 0
  9. },
  10. "hits" : {
  11. "total" : {
  12. "value" : 2,
  13. "relation" : "eq"
  14. },
  15. "max_score" : 1.0,
  16. "hits" : [
  17. {
  18. "_index" : "my-index-000001",
  19. "_type" : "_doc",
  20. "_id" : "1",
  21. "_score" : 1.0,
  22. "_source" : {
  23. "status_code" : null
  24. }
  25. },
  26. {
  27. "_index" : "my-index-000001",
  28. "_type" : "_doc",
  29. "_id" : "2",
  30. "_score" : 1.0,
  31. "_source" : {
  32. "status_code" : [ ]
  33. }
  34. }
  35. ]
  36. }
  37. }

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


  
  1. GET my- index- 000001/_search
  2. {
  3. "query": {
  4. "term": {
  5. "status_code": "NULL"
  6. }
  7. }
  8. }

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


  
  1. {
  2. "took" : 1,
  3. "timed_out" : false,
  4. "_shards" : {
  5. "total" : 1,
  6. "successful" : 1,
  7. "skipped" : 0,
  8. "failed" : 0
  9. },
  10. "hits" : {
  11. "total" : {
  12. "value" : 1,
  13. "relation" : "eq"
  14. },
  15. "max_score" : 0.2876821,
  16. "hits" : [
  17. {
  18. "_index" : "my-index-000001",
  19. "_type" : "_doc",
  20. "_id" : "1",
  21. "_score" : 0.2876821,
  22. "_source" : {
  23. "status_code" : null
  24. }
  25. }
  26. ]
  27. }
  28. }

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

 

例子二

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


  
  1. PUT twitter /_doc/ 1
  2. {
  3. "age": null
  4. }
  5. PUT twitter /_doc/ 2
  6. {
  7. "age": 20
  8. }

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


  
  1. GET twitter/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "avg_age": {
  6. "avg": {
  7. "field": "age"
  8. }
  9. }
  10. }
  11. }

那么上面的聚合返回:


  
  1. {
  2. "took" : 2,
  3. "timed_out" : false,
  4. "_shards" : {
  5. "total" : 1,
  6. "successful" : 1,
  7. "skipped" : 0,
  8. "failed" : 0
  9. },
  10. "hits" : {
  11. "total" : {
  12. "value" : 2,
  13. "relation" : "eq"
  14. },
  15. "max_score" : null,
  16. "hits" : [ ]
  17. },
  18. "aggregations" : {
  19. "avg_age" : {
  20. "value" : 20.0
  21. }
  22. }
  23. }

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


  
  1. DELETE twitter
  2. PUT twitter
  3. {
  4. "mappings": {
  5. "properties": {
  6. "age": {
  7. "type": "float",
  8. "null_value": 0
  9. }
  10. }
  11. }
  12. }

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


  
  1. PUT twitter /_doc/ 1
  2. {
  3. "age": null
  4. }
  5. PUT twitter /_doc/ 2
  6. {
  7. "age": 20
  8. }

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


  
  1. GET twitter/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "avg_age": {
  6. "avg": {
  7. "field": "age"
  8. }
  9. }
  10. }
  11. }

上面的结果为:


  
  1. {
  2. "took" : 703,
  3. "timed_out" : false,
  4. "_shards" : {
  5. "total" : 1,
  6. "successful" : 1,
  7. "skipped" : 0,
  8. "failed" : 0
  9. },
  10. "hits" : {
  11. "total" : {
  12. "value" : 2,
  13. "relation" : "eq"
  14. },
  15. "max_score" : null,
  16. "hits" : [ ]
  17. },
  18. "aggregations" : {
  19. "avg_age" : {
  20. "value" : 10.0
  21. }
  22. }
  23. }

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

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


  
  1. DELETE twitter
  2. PUT twitter
  3. {
  4. "mappings": {
  5. "properties": {
  6. "age": {
  7. "type": "float",
  8. "null_value": 0
  9. }
  10. }
  11. }
  12. }
  13. PUT twitter /_doc/ 1
  14. {
  15. "content": "This is cool"
  16. }
  17. PUT twitter /_doc/ 2
  18. {
  19. "age": 20,
  20. "content": "This is cool too!"
  21. }

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


  
  1. GET twitter/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "avg_age": {
  6. "avg": {
  7. "field": "age"
  8. }
  9. }
  10. }
  11. }

其显示结果为:


  
  1. {
  2. "took" : 1,
  3. "timed_out" : false,
  4. "_shards" : {
  5. "total" : 1,
  6. "successful" : 1,
  7. "skipped" : 0,
  8. "failed" : 0
  9. },
  10. "hits" : {
  11. "total" : {
  12. "value" : 2,
  13. "relation" : "eq"
  14. },
  15. "max_score" : null,
  16. "hits" : [ ]
  17. },
  18. "aggregations" : {
  19. "avg_age" : {
  20. "value" : 20.0
  21. }
  22. }
  23. }

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


转载:https://blog.csdn.net/UbuntuTouch/article/details/114266732
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场