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

Finding top N entries per group in Arango

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

Example purpose: Find the top 2 employees in each department by most years of experience.

示例数据:

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

_id name
departments/1 engineering
departments/2 sales

"dept_emp_edges" 是一个通过 id 连接部门和员工对象的边缘集合。

_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 还很陌生,我还能做些什么来确保这是有效的?

您的第一个查询不正确 (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}

对于您的示例数据库,此 returns:

[
  {
    "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 字段上的索引可能会有所帮助(Explain 建议这样做)。