【问题标题】:How to search Parent documents along with count of associated child documents如何搜索父文档以及相关子文档的数量
【发布时间】:2020-04-20 11:21:04
【问题描述】:

我正在寻找一种最佳方式来搜索父文档以及相关子文档的计数? 示例: 我们有组织文件和用户文件。可能有成千上万的用户属于一个特定的组织。

组织文件:

{
   "id" : "001"
   "name" : "orgname1"
}
{
   "id" : "002"
   "name" : "orgname2"
}

用户文档:

{
   "id" : "testusr1"
   "name" : "xyz1"
   "orgId" : "001"
},
{
   "id" : "testusr2"
   "name" : "xyz2"
   "orgId" : "001"
}
{
   "id" : "testusr3"
   "name" : "xyz3"
   "orgId" : "001"
}
{
   "id" : "testusr4"
   "name" : "xyz4"
   "orgId" : "001"
}
{
   "id" : "testusr5"
   "name" : "xyz5"
   "orgId" : "002"
}
{
   "id" : "testusr6"
   "name" : "xyz6"
   "orgId" : "002"
}

在上面的示例中,我们有 4 个用户与组织相关联,001 和 2 个用户与 002 相关联。所以在前端,管理员将搜索组织,结果,我想给出响应以及该组织的用户数.

【问题讨论】:

    标签: elasticsearch


    【解决方案1】:

    您可以通过三种方式解决您的问题。各有优缺点

    1.分别索引父子节点

    这将需要两个查询。首先需要查询用户索引并获取orgId,然后查询子索引并获取其计数

    优势。

    一个索引的变化不会影响其他索引

    缺点。

    你需要使用两个查询

    2. Nested Documents

    映射:

    PUT index9
    {
      "mappings": {
        "properties": {
          "id":{
            "type": "integer"
          },
          "name":{
            "type": "text",
            "fields": {
              "keyword":{
                "type":"keyword"
              }
            }
          },
          "user":{
            "type": "nested",
            "properties": {
              "id":{
                "type":"text",
                "fields":{
                  "keyword":{
                  "type":"keyword"
                  }
                }
              },
              "name":{
                "type":"text",
                "fields":{
                  "keyword":{
                  "type":"keyword"
                  }
                }
              }
            }
          }
        }
      }
    }
    
    
    POST index9/_doc
    {
      "id" : 1,
      "name" : "orgname1",
      "user":[
               {
                 "id":"testuser1",
                 "name":"xyz1"
               },
               {
                 "id":"testuser2",
                 "name":"xyz2"
               }
             ]
    }
    
    

    查询:

    GET index9/_search
    {
      "query": {
        "match_all": {}
      },
      "aggs": {
        "organization": {
          "terms": {
            "field": "id",
            "size": 10
          },
          "aggs": {
            "user": {
              "nested": {
                "path": "user"
              },
              "aggs": {
                "count": {
                  "value_count": {
                    "field": "user.id.keyword"
                  }
                }
              }
            }
          }
        }
      }
    }
    

    结果:

    "aggregations" : {
        "organization" : {
          "doc_count_error_upper_bound" : 0,
          "sum_other_doc_count" : 0,
          "buckets" : [
            {
              "key" : 1,
              "doc_count" : 1,
              "user" : {
                "doc_count" : 2,
                "count" : {
                  "value" : 2
                }
              }
            }
          ]
        }
      }
    

    与父/子相比,嵌套更快, 嵌套文档需要重新索引父级及其所有子级,而父级子级允许重新索引/添加/删除特定子级。

    3. Parent Child Relationship

    映射

    {
      "my_index" : {
        "mappings" : {
          "properties" : {
            "id" : {
              "type" : "keyword"
            },
            "my_join_field" : {
              "type" : "join",
              "eager_global_ordinals" : true,
              "relations" : {
                "organization" : "user"
              }
            },
            "name" : {
              "type" : "text"
            },
            "orgId" : {
              "type" : "long"
            }
          }
        }
      }
    

    数据:

    POST my_index/_doc/1
    {
      "id": 1,
      "name" : "orgname1",
      "my_join_field": "organization" 
    }
    
    POST my_index/_doc/2
    {
      "id" : 2,
      "name" : "orgname2",
      "my_join_field": "organization" 
    }
    
    POST my_index/_doc/3?routing=1
    {
      "id": "testusr1",
      "name": "xyz1",
      "orgId": 1,
      "my_join_field": {
        "name": "user",
        "parent": 1
      }
    }
    
    POST my_index/_doc/4?routing=2
    {
       "id" : "testusr5",
       "name" : "xyz5",
       "orgId" : 1,
       "my_join_field": {
        "name": "user",
        "parent": 2
      }
    }
    
    POST my_index/_doc/5?routing=2
    {
       "id" : "testusr6",
       "name" : "xyz6",
       "orgId" : 2,
       "my_join_field": {
        "name": "user",
        "parent": 2
      }
    }
    

    查询:

    {
      "query": {
        "has_child": {
          "type": "user",
          "query": { "match_all": {} }
        }
      },
      "aggs": {
        "organization": {
          "terms": {
            "field": "id",
            "size": 10
          },
          "aggs": {
            "user": {
              "children": {
                "type": "user"
              },
              "aggs": {
                "count": {
                  "value_count": {
                    "field": "id"
                  }
                }
              }
            }
          }
        }
      }
    }
    

    结果:

    "hits" : [
          {
            "_index" : "my_index",
            "_type" : "_doc",
            "_id" : "1",
            "_score" : 1.0,
            "_source" : {
              "id" : 1,
              "name" : "orgname1",
              "my_join_field" : "organization"
            }
          },
          {
            "_index" : "my_index",
            "_type" : "_doc",
            "_id" : "2",
            "_score" : 1.0,
            "_source" : {
              "id" : 2,
              "name" : "orgname2",
              "my_join_field" : "organization"
            }
          }
        ]
      },
      "aggregations" : {
        "organization" : {
          "doc_count_error_upper_bound" : 0,
          "sum_other_doc_count" : 0,
          "buckets" : [
            {
              "key" : "1",
              "doc_count" : 1,
              "user" : {
                "doc_count" : 1,
                "count" : {
                  "value" : 1
                }
              }
            },
            {
              "key" : "2",
              "doc_count" : 1,
              "user" : {
                "doc_count" : 2,
                "count" : {
                  "value" : 2
                }
              }
            }
          ]
        }
    

    好处: 1.父文档和子文档是分开的文档

    1. 父子节点可以单独更新,无需重新索引对方

    2. 当子文档数量较多且需要添加或 经常更换。

    3. 子文档可以作为搜索请求的结果返回。

    【讨论】:

    • 非常感谢您对这个问题的精彩回答。我想选择选项#1。
    • 很高兴能帮上忙。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-19
    相关资源
    最近更新 更多