在 Arango 中查找每组的前 N ​​个条目

Posted

技术标签:

【中文标题】在 Arango 中查找每组的前 N ​​个条目【英文标题】:Finding top N entries per group in Arango 【发布时间】:2021-11-15 10:01:03 【问题描述】:

我正在尝试在 Arango (AQL) 中按组有效地查找排名靠前的条目。我有一个相当标准的对象集合和一个代表该部门的部门和员工的边缘集合。

示例目的:找出每个部门中经验最多的前 2 名员工。

样本数据:

“部门”是一个对象集合。以下是一些条目:

_id name
departments/1 engineering
departments/2 sales

“dept_emp_edges”是一个边集合,通过 ids 连接部门和员工对象。

_id _from _to years_exp
dept_emp_edges/1 departments/1 employees/1 3
dept_emp_edges/2 departments/1 employees/2 4
dept_emp_edges/3 departments/1 employees/3 5
dept_emp_edges/4 departments/2 employees/1 6

我希望以大多数年的经验得到每个部门前 2 名的员工:

department employee years_exp
departments/1 employee/3 5
departments/1 employee/2 4
departments/2 employee/1 6

长时间工作的查询

以下查询有效!但是在较大的表上有点慢,感觉效率低。

FOR dept IN departments
    LET top2earners = (
        FOR dep_emp_edge IN dept_emp_edges
            FILTER dep_emp_edge._from == dept._id
            SORT dep_emp_edge.years_exp DESC
            LIMIT 2
            RETURN 'department': dep_emp_edge._from,
                    'employee': dep_emp_edge._to,
                    'years_exp': dep_emp_edge.years_exp
        )

    FOR row in top2earners
        return 'department': dep_emp_edge._from,
                'employee': dep_emp_edge._to,
                'years_exp': dep_emp_edge.years_exp

我不喜欢这样,因为这里有3个循环,感觉效率很低。

短查询

但是,我试着写:

FOR dept IN departments
    FOR dep_emp_edge IN dept_emp_edges
        FILTER dep_emp_edge._from == dept._id
        SORT dep_emp_edge.years_exp DESC
        LIMIT 2
        RETURN 'department': dep_emp_edge._from,
                'employee': dep_emp_edge._to,
                'years_exp': dep_emp_edge.years_exp

但最后一个查询只输出最终部门的前 2 个结果。不是每个部门的所有前 2 名。

我的问题是:(1)为什么第二个较短的查询没有给出所有结果? (2) 我对 Arango 和 ArangoQL 还很陌生,我还可以做些什么来确保这有效?

【问题讨论】:

你能分享第一个查询的解释输出吗? 【参考方案1】:

你的第一个查询写的不正确 (Query: AQL: collection or view not found: dep_emp_edge (while parsing)) - 我只能猜到你的意思,我暂时忽略它。

您较小的查询将整体结果限制为两个 - 直观地相反 - 因为您没有按部门分组。

我建议一种稍微不同的方法:使用边缘集合作为中心源并按 _from 分组,每个部门返回一个文档,其中包含两个排名靠前的员工的数组(如果他们存在的话),而不是每个员工一个文档:

FOR edge IN dept_emp_edges
  SORT edge.years_exp DESC
  COLLECT dep = edge._from INTO deps
  LET emps = (
    FOR e in deps
       LIMIT 2
       RETURN ZIP(["employee", "years_exp"], [e.edge._to, e.edge.years_exp])
  )
  RETURN "department": dep, employees: emps

对于您的示例数据库,这将返回:

[
  
    "department": "departments/1",
    "employees": [
      
        "employee": "employees/3",
        "years_exp": 5
      ,
      
        "employee": "employees/2",
        "years_exp": 4
      
    ]
  ,
  
    "department": "departments/2",
    "employees": [
      
        "employee": "employees/1",
        "years_exp": 6
      
    ]
  
]

如果查询太慢,dept_emp_edges 集合的year_exp 字段上的索引可能会有所帮助(解释建议这样做)。

【讨论】:

以上是关于在 Arango 中查找每组的前 N ​​个条目的主要内容,如果未能解决你的问题,请参考以下文章

MySQL分组查询后如何获取每组的前N条数据,你会吗?

获取每组的前 n 个结果 [重复]

t-SQL 查找每个组的前 10 条记录

Oracle分组查询取每组排序后的前N条记录

mysql分组后,取每组的前3条数据(并且有顺序)

oracle开展分组后,取出每组的前几条数据