【问题标题】:Optimize Query in arangodb优化 arangodb 中的查询
【发布时间】:2018-04-23 07:51:33
【问题描述】:

我在 arangodb 中运行以下查询:

LET catalogDatasets = []
LET openDatasets = ( FOR d IN datasets FILTER d.visibility == "open"  RETURN d._id )
LET myDatasets = []
LET myPurchasedDatasets = []
LET searchTarget = UNIQUE( UNION( catalogDatasets, openDatasets, myDatasets, myPurchasedDatasets ) )

LET unorderedDatasetsIds = (
    FOR dataset IN FULLTEXT(datasets, "word_list", @searchWords)
     FILTER dataset._id IN searchTarget  RETURN dataset._id
)

LET ordered = (
    FOR wl IN wordLinks
    FILTER wl._from IN unorderedDatasetsIds
    FOR x IN words
        FILTER x._id == wl._to
        COLLECT did = wl._from INTO score = wl.invFq/(x.numEdges+@epsilon)
        SORT score
        LIMIT 0, 20
       RETURN did
)
RETURN {
    dids: ordered,
    number_of_items: LENGTH(unorderedDatasetsIds)
}

我的搜索词都使用如下前缀:

pref:banana,|pref:chocollate

基本上我想优化这个查询,因为它需要大约 2 秒才能返回。我的想法之一是将全文搜索中的项目数限制为 1000,但是这样做,数据集将是随机的,因为它将取决于 arangodb 返回查询的顺序。

我可以对该查询应用哪些优化以使其更快?

P.S.:我有一个空数据集的联合,但有时它们不是空的。就发生在这个查询的情况下。

编辑 我的查询解释:

Query string:
 LET catalogDatasets = []
 LET openDatasets = ( FOR d IN datasets FILTER d.visibility == "open"  RETURN d._id )
 LET myDatasets = []
 LET myPurchasedDatasets = []
 LET searchTarget = UNIQUE( UNION( catalogDatasets, openDatasets, myDatasets, myPurchasedDatasets ) )
 LET unorderedDatasetsIds = (
     FOR dataset IN FULLTEXT(datasets, "word_list", @searchWords)
      FILTER dataset._id IN searchTarget  RETURN dataset._id
 )
 LET ordered = (
     FOR wl IN wordLinks
     FILTER wl._from IN unorderedDatasetsIds
     FOR x IN words
         FILTER x._id == wl._to
         COLLECT did = wl._from INTO score = wl.invFq/(x.numEdges+@epsilon)
         SORT score
         LIMIT 0, 20
        RETURN did
 )
 RETURN {
     dids: ordered,
     number_of_items: LENGTH(unorderedDatasetsIds)
 }

Execution plan:
 Id   NodeType                  Est.   Comment
  1   SingletonNode                1   * ROOT
  9   SubqueryNode                 1     - LET openDatasets = ...   /* const subquery */
  3   SingletonNode                1       * ROOT
  4   EnumerateCollectionNode   9752         - FOR d IN datasets   /* full collection scan */
  5   CalculationNode           9752           - LET #19 = (d.`visibility` == "open")   /* simple expression */   /* collections used: d : datasets */
  6   FilterNode                9752           - FILTER #19
  7   CalculationNode           9752           - LET #21 = d.`_id`   /* attribute expression */   /* collections used: d : datasets */
  8   ReturnNode                9752           - RETURN #21
 41   CalculationNode              1     - LET #39 = SORTED_UNIQUE(UNIQUE(UNION([ ], openDatasets, [ ], [ ])))   /* simple expression */
 20   SubqueryNode                 1     - LET unorderedDatasetsIds = ...   /* subquery */
 13   SingletonNode                1       * ROOT
 38   IndexNode                 9752         - FOR dataset IN datasets   /* fulltext index scan */
 16   CalculationNode           9752           - LET #25 = (dataset.`_id` in /* sorted */ #39)   /* simple expression */   /* collections used: dataset : datasets */
 17   FilterNode                9752           - FILTER #25
 18   CalculationNode           9752           - LET #27 = dataset.`_id`   /* attribute expression */   /* collections used: dataset : datasets */
 19   ReturnNode                9752           - RETURN #27
 34   SubqueryNode                 1     - LET ordered = ...   /* subquery */
 21   SingletonNode                1       * ROOT
 40   IndexNode                  410         - FOR wl IN wordLinks   /* edge index scan */
 28   CalculationNode            410           - LET #33 = wl.`_from`   /* attribute expression */   /* collections used: wl : wordLinks */
 39   IndexNode                  410           - FOR x IN words   /* primary index scan */
 37   SortNode                   410             - SORT #33 ASC
 29   CalculationNode            410             - LET #35 = (wl.`invFq` / (x.`numEdges` + 0.1))   /* simple expression */   /* collections used: wl : wordLinks, x : words */
 30   CollectNode                328             - COLLECT did = #33 INTO score = #35   /* sorted */
 31   SortNode                   328             - SORT score ASC
 32   LimitNode                   20             - LIMIT 0, 20
 33   ReturnNode                  20             - RETURN did
 35   CalculationNode              1     - LET #37 = { "dids" : ordered, "number_of_items" : LENGTH(unorderedDatasetsIds) }   /* simple expression */
 36   ReturnNode                   1     - RETURN #37

Indexes used:
 By   Type       Collection   Unique   Sparse   Selectivity   Fields               Ranges
 38   fulltext   datasets     false    true             n/a   [ `word_list` ]      FULLTEXT(datasets   /* all collection documents */, "word_list", "'prefix:トウ,|prefix:とう'")
 40   edge       wordLinks    false    false         3.05 %   [ `_from`, `_to` ]   (wl.`_from` in unorderedDatasetsIds)
 39   primary    words        true     false       100.00 %   [ `_key` ]           (x.`_id` == wl.`_to`)

Optimization rules applied:
 Id   RuleName
  1   move-calculations-up
  2   move-filters-up
  3   remove-redundant-calculations
  4   remove-unnecessary-calculations
  5   move-calculations-up-2
  6   move-filters-up-2
  7   fulltext-index-optimizer
  8   use-indexes
  9   remove-filter-covered-by-index
 10   sort-in-values
 11   remove-unnecessary-calculations-2
 12   move-calculations-down

【问题讨论】:

  • 您能分享一下用户界面中查询编辑器的Explain 的输出吗?
  • 完成。我编辑了我的问题。
  • 如果在 datasets.visibility 上添加稀疏非唯一索引,性能会如何变化?当您想要返回分页结果时,最好的性能是执行完整查询,首先应用过滤,然后应用排序,然后使用 limit 根据传递给查询的页面参数为返回的值提供开始/结束值, (注意 LIMIT 可以传递两个参数)。另外,您的searchwords 格式是pref:banana,|pref:chocollate 还是prefix:banana,|prefix:chocollate
  • 以下内容对您有什么好处吗?

标签: graph full-text-search query-optimization arangodb aql


【解决方案1】:

好的。一个艰难的提议。查询非常昂贵。但我尝试了一些东西:

LET catalogDatasets = []
LET myDatasets = []
LET myPurchasedDatasets = []
LET searchTarget = UNIQUE( UNION( catalogDatasets, myDatasets, myPurchasedDatasets ) )
LET unorderedDatasetsIds = (
  FOR dataset IN FULLTEXT(datasets, "word_list", @searchWords)
    FILTER dataset._id IN searchTarget || d.visibility == "open" RETURN dataset._id
 )
 LET ordered = (
   FOR wl IN wordLinks
     FILTER wl._from IN unorderedDatasetsIds
     FOR x IN words
       FILTER x._id == wl._to
       COLLECT did = wl._from INTO score = wl.invFq/(x.numEdges+@epsilon)
       SORT score
       LIMIT 0, 20
       RETURN did
 )
 RETURN {
     dids: ordered,
     number_of_items: LENGTH(unorderedDatasetsIds)
}

在这里看不到任何明显的东西。但是如果"open" 的数量不多,那么显然让openDatasets 的查询消失应该很重要。

【讨论】:

  • 最后我们改变了查询的方式,但实际上这个方法将查询速度从 2.5 提高到了 1.5。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-08
  • 2011-09-14
  • 1970-01-01
  • 2015-09-25
  • 2012-06-15
相关资源
最近更新 更多