Nested 数据类型

nested 类型是特殊的object类型,它可以使对象数组已相对独立的查询方式进行索引。

对象数组是如何展平的

内部对象数组的字段并不是期望的那样工作。Lucene 并没有内部对象的概念,所以 elasticsearch 展平了对象的层级,变成了字段名称和值的简单列表。如:

  1. PUT my_index/_doc/1
  2. {
  3. "group" : "fans",
  4. "user" : [
  5. {
  6. "first" : "John",
  7. "last" : "Smith"
  8. },
  9. {
  10. "first" : "Alice",
  11. "last" : "White"
  12. }
  13. ]
  14. }

自动添加了object类型的 user字段。

该文档将会在内部转换为如下的文档:

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

其中user.firstuser.last字段将会被展平为多值字段,而alicewhite的关联关系丢失了。当查询alice AND smith时会错误的匹配到该文档。

  1. GET my_index/_search
  2. {
  3. "query": {
  4. "bool": {
  5. "must": [
  6. { "match": { "user.first": "Alice" }},
  7. { "match": { "user.last": "Smith" }}
  8. ]
  9. }
  10. }
  11. }

使用 nested类型的对象数组

如果希望索引对象数组,并保持数组中每个对象的独立性,应该使用nested类型,而不是object类型。在内部,嵌套类型将数组中的对象索引为独立的隐藏文档,意味着使用nested 查询,可以独立的查询每个嵌套对象。

  1. PUT my_index
  2. {
  3. "mappings": {
  4. "_doc": {
  5. "properties": {
  6. "user": {
  7. "type": "nested"
  8. }
  9. }
  10. }
  11. }
  12. }
  13. PUT my_index/_doc/1
  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. GET my_index/_search
  28. {
  29. "query": {
  30. "nested": {
  31. "path": "user",
  32. "query": {
  33. "bool": {
  34. "must": [
  35. { "match": { "user.first": "Alice" }},
  36. { "match": { "user.last": "Smith" }}
  37. ]
  38. }
  39. }
  40. }
  41. }
  42. }
  43. GET my_index/_search
  44. {
  45. "query": {
  46. "nested": {
  47. "path": "user",
  48. "query": {
  49. "bool": {
  50. "must": [
  51. { "match": { "user.first": "Alice" }},
  52. { "match": { "user.last": "White" }}
  53. ]
  54. }
  55. },
  56. "inner_hits": {
  57. "highlight": {
  58. "fields": {
  59. "user.first": {}
  60. }
  61. }
  62. }
  63. }
  64. }
  65. }

user 字段主动映射为 nested 类型;

第一个查询不会命中, Alice and Smith并不在同一个嵌套文档中;

第二个查询成功命中;

inner_hits可以高亮匹配到的嵌套文档;

嵌套文档可以:

nested 类型的参数

dynamic:新属性是否可以动态的添加到 nested 类型的对象中,true(默认),false,strict;

properties:嵌套对象中的字段,可以是任意数据类型,包括 nested。可以将新属性添加到现有的嵌套类型对象中。

注:

因为嵌套类型的文档被索引在独立的文档中,它们仅可以通过 nested查询、nested/reverse_nested 聚合,或者 nested inner hits 访问。

例如,嵌套文档中的一个字符串字段设置了 index_optionsoffsetto allow use of the postings,在标记阶段,这些 offsets 在主要标记阶段不会生效。相反,高亮操作需要通过 nested inner hits 执行。(不懂这句)

限制 nested 类型字段的数量

索引一个 100 个嵌套字段的文档,实际上索引了 101 个文档(一个嵌套字段会产生一个隐藏文档,并不是一个嵌套数组的对象产生一个隐藏文档???),因为每一个嵌套文档都被索引一个单独的文档。为了防止定义不明确的映射,每个索引可以定义的嵌套字段数量限制在 50 个。

翻译自:https://www.elastic.co/guide/en/elasticsearch/reference/6.3/nested.html