ArangoDB分面搜索性能

7
我们正在评估ArangoDB在facets计算方面的性能。有许多其他产品可以通过特殊API或查询语言来完成相同的任务,例如:
  • MarkLogic Facets
  • ElasticSearch Aggregations
  • Solr Faceting等
我们了解到,在Arango中没有专门的API来显式地计算facets。但实际上,并不需要它,因为由于全面的AQL,可以通过简单的查询轻松实现。例如:
 FOR a in Asset 
  COLLECT attr = a.attribute1 INTO g
 RETURN { value: attr, count: length(g) }

这个查询计算属性1的分面,并以以下形式呈现频率:
[
  {
    "value": "test-attr1-1",
    "count": 2000000
  },
  {
    "value": "test-attr1-2",
    "count": 2000000
  },
  {
    "value": "test-attr1-3",
    "count": 3000000
  }
]

它表示,在我的整个集合中,attribute1 有三种形式(test-attr1-1、test-attr1-2 和 test-attr1-3),并提供了相关的计数。基本上,我们运行了一个去重查询和聚合计数。
看起来很简单、干净。但只有一个非常大的问题——性能。
在仅有 800 万个文档的测试集合中,上述查询需要花费 31 秒的时间。我们尝试了不同的索引类型、存储引擎(包括 rocksdb 和非 rocksdb),并调查了解释计划,但均无果。
我们在此处将不胜感激地接受任何意见。要么我们做错了什么,要么 ArangoDB 简单地没有被设计成在这个特定领域中执行。
顺便说一下,最终目标是在不到一秒钟的时间内运行类似以下内容的查询:
LET docs = (FOR a IN Asset 

  FILTER a.name like 'test-asset-%'

  SORT a.name

 RETURN a)

LET attribute1 = (

 FOR a in docs 

  COLLECT attr = a.attribute1 INTO g

 RETURN { value: attr, count: length(g[*])}

)

LET attribute2 = (

 FOR a in docs 

  COLLECT attr = a.attribute2 INTO g

 RETURN { value: attr, count: length(g[*])}

)

LET attribute3 = (

 FOR a in docs 

  COLLECT attr = a.attribute3 INTO g

 RETURN { value: attr, count: length(g[*])}

)

LET attribute4 = (

 FOR a in docs 

  COLLECT attr = a.attribute4 INTO g

 RETURN { value: attr, count: length(g[*])}

)

RETURN {

  counts: (RETURN {

    total: LENGTH(docs), 

    offset: 2, 

    to: 4, 

    facets: {

      attribute1: {

        from: 0, 

        to: 5,

        total: LENGTH(attribute1)

      },

      attribute2: {

        from: 5, 

        to: 10,

        total: LENGTH(attribute2)

      },

      attribute3: {

        from: 0, 

        to: 1000,

        total: LENGTH(attribute3)

      },

      attribute4: {

        from: 0, 

        to: 1000,

        total: LENGTH(attribute4)

      }

    }

  }),

  items: (FOR a IN docs LIMIT 2, 4 RETURN {id: a._id, name: a.name}),

  facets: {

    attribute1: (FOR a in attribute1 SORT a.count LIMIT 0, 5 return a),

    attribute2: (FOR a in attribute2 SORT a.value LIMIT 5, 10 return a),

    attribute3: (FOR a in attribute3 LIMIT 0, 1000 return a),

    attribute4: (FOR a in attribute4 SORT a.count, a.value LIMIT 0, 1000 return a)

   }

}

谢谢!

1个回答

6

原来主线程已经在ArangoDB Google Group上发生了。

这里是完整讨论链接

以下是当前解决方案的摘要:

  • 从特定功能分支运行Arango的自定义版本,其中进行了大量性能改进(希望它们很快就能成为主要发布的一部分)
  • 不需要索引来计算facets
  • MMFiles是首选存储引擎
  • AQL应该编写为使用“COLLECT attr = a.attributeX WITH COUNT INTO length”而不是“count:length(g)”
  • AQL应该分成较小的部分并并行运行(我们正在运行Java8的Fork/Join来扩展facets AQLs,然后将它们合并成最终结果)
  • 一个AQL用于过滤/排序和检索主实体(如果需要,在排序/过滤时添加相应的skiplist索引)
  • 其余是每个facet值/频率对的小型AQL

最终,与上述原始AQL相比,我们获得了> 10倍的性能提升。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接