Nested

原文链接 : https://www.elastic.co/guide/en/elasticsearch/reference/current/nested.html#nested

译文链接 : Nested

贡献者 : 彭秋源ApacheCNApache中文网

嵌套数据类型

nested类型是一种对象类型的特殊版本,它允许索引对象数组,独立地索引每个对象。

如何使对象数组变扁平

内部类对象数组并不以你预料的方式工作。Lucene没有内部对象的概念,所以Elasticsearch将对象层次扁平化,转化成字段名字和值构成的简单列表。比如,以下的文档:

  1. curl -XPUT 'localhost:9200/my_index/my_type/1?pretty' -d'
  2. {
  3. "group" : "fans",
  4. "user" : [ // 1
  5. {
  6. "first" : "John",
  7. "last" : "Smith"
  8. },
  9. {
  10. "first" : "Alice",
  11. "last" : "White"
  12. }
  13. ]
  14. }'

user字段作为对象动态添加

在内部被转化成如下格式的文档:

  1. {
  2. "group" : "fans",
  3. "user.first" : [ "alice", "john" ],
  4. "user.last" : [ "smith", "white" ]
  5. }

user.firstuser.last扁平化为多值字段,alicewhite的关联关系丢失了。导致这个文档错误地匹配对 alicesmith的查询:

  1. curl -XGET 'localhost:9200/my_index/_search?pretty' -d'
  2. {
  3. "query": {
  4. "bool": {
  5. "must": [
  6. { "match": { "user.first": "Alice" }},
  7. { "match": { "user.last": "Smith" }}
  8. ]
  9. }
  10. }
  11. }'

使用nested字段对应object数组

如果你需要索引对象数组,并且保持数组中每个对象的独立性,你应该使用nested对象类型而不是object类型。nested对象将数组中每个对象作为独立隐藏文档来索引,这意味着每个嵌套对象都可以独立被搜索:

  1. curl -XPUT 'localhost:9200/my_index?pretty' -d'
  2. {
  3. "mappings": {
  4. "my_type": {
  5. "properties": {
  6. "user": {
  7. "type": "nested" // 1
  8. }
  9. }
  10. }
  11. }
  12. }'
  13. curl -XPUT 'localhost:9200/my_index/my_type/1?pretty' -d'
  14. {
  15. "group" : "fans",
  16. "user" : [
  17. {
  18. "first" : "John",
  19. "last" : "Smith"
  20. },
  21. {
  22. "first" : "Alice",
  23. "last" : "White"
  24. }
  25. ]
  26. }'
  27. curl -XGET 'localhost:9200/my_index/_search?pretty' -d'
  28. {
  29. "query": {
  30. "nested": {
  31. "path": "user",
  32. "query": {
  33. "bool": {
  34. "must": [
  35. { "match": { "user.first": "Alice" }},
  36. { "match": { "user.last": "Smith" }} // 2
  37. ]
  38. }
  39. }
  40. }
  41. }
  42. }'
  43. curl -XGET 'localhost:9200/my_index/_search?pretty' -d'
  44. {
  45. "query": {
  46. "nested": {
  47. "path": "user",
  48. "query": {
  49. "bool": {
  50. "must": [
  51. { "match": { "user.first": "Alice" }},
  52. { "match": { "user.last": "White" }} // 3
  53. ]
  54. }
  55. },
  56. "inner_hits": { // 4
  57. "highlight": {
  58. "fields": {
  59. "user.first": {}
  60. }
  61. }
  62. }
  63. }
  64. }
  65. }'

| 1 | user 字段映射为 nested 类型而不是 objec t类型 | | 2 | 该查询没有匹配,因为 AliceSmith 不在同一个嵌套类中 | | 3 | 该查询有匹配,因为 AliceWhite 在同一个嵌套类中 | | 4 | inner_hits 可以高亮匹配的嵌套文档 |

嵌套文档可以:

| 1 | 使用nested`查询来搜索 | | 2 | 使用nested和 [reverse_nested`](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-reverse-nested-aggregation.html “Reverse nested Aggregation”)聚合来分析 | | 3 | 使用 nested sorting来排序 | | 4 | 使用 nested inner hits 来检索和高亮 |

nested字段参数

| 参数 | 说明 | | dynamic | 新属性是否应动态添加到现有对象。接受 true (默认), false 和 strict。 | | include_in_all | 为对象中的所有属性设置默认的 include_in_all 值,对象本身没有添加到 _all 字段。 | | properties | 对象内的字段,可以是任何数据类型,包括对象。可以将新属性添加到现有对象。 |

注意

因为嵌套文档是作为单独的文档被索引的,所以嵌套文档只能被 nested 查询、nested / reverse_nested或者 nested inner hits 访问。 比如,一个 string 字段包含嵌套文档,嵌套文档中 index_options 设置为 offsets 以使用 postings highlighter,这些偏移量在主要的高亮阶段是不可用的。必须通过 nested inner hits 来进行高亮操作。

限制nested字段的数量

索引一个包含 100 个 nested字段的文档实际上就是索引 101 个文档,每个嵌套文档都作为一个独立文档来索引。为了防止过度定义嵌套字段的数量,每个索引可以定义的嵌套字段被限制在 50 个。