在couchbase 4.0中查询的复合键

时间:2016-01-04 12:13:47

标签: python couchbase composite-key querying couchbase-view

我得到了这样的观点:

function (doc, meta) {
  if(doc.type){
    var id = doc.id ? doc.id: "";
    var company = doc.company ? doc.company: "";
    var store = doc.store ? doc.store: "";

    emit([doc.type, id, company, store]);
  }
}

并且所有文件都包含类型和其他3个字段的组合,具体取决于类型。 我想通过以下函数通过此视图进行一般查询:

def find_by_type_pageing_by_id_company_store(self, format_function=None, page=None, rows=None, recent=None, type=None, id="", company="", store="", include_docs=True):

    if not type:
        logger.error("No Type Provided in find by type query")
        raise exceptions.InvalidQueryParams("No Type Provided in find by type query")

    view = VIEW_BY_TYPE_VIN_COMPANY_STORE

    cb = self.get_cb_bucket()

    query = Query()

    # 'recent' and 'rows' are equivalent and will be unified to 'limit' here
    if recent and rows:
        raise exceptions.InvalidQueryParams(detail="Query may not contain both 'recent' and 'rows'")
    limit = rows or recent

    if limit:
        try:
            rows_per_page = int(limit)
        except ValueError:
            raise exceptions.InvalidQueryParams(detail="Query params 'recent' and 'rows' have to be integers")

        if rows_per_page > settings.PAGINATION_MAX_ROWS_LIMIT:
            raise exceptions.InvalidQueryParams(detail="Query params 'recent' and 'rows' may not exceed %s. "
                                                "Use the additional param 'page=2', 'page=3', etc. to access "
                                                "more objects" % settings.PAGINATION_MAX_ROWS_LIMIT)
        try:
            page = 1 if page is None else int(page)
        except ValueError:
            raise exceptions.InvalidQueryParams(detail="Query param 'page' has to be an integer")

        skip = rows_per_page * (page - 1)

        query.limit = rows_per_page
        query.skip = skip

    query.mapkey_range = [
        [type, id, company, workshop],
        [type, id + query.STRING_RANGE_END, company + query.STRING_RANGE_END, store + query.STRING_RANGE_END]
    ]

    rows = cb.query(view['doc'], view['view'], include_docs=include_docs, query=query)

    if format_function is None:
        format_function = self.format_function_default

    return_array = format_function(rows)
    return return_array

只查询某种类型,类型和id范围时,它可以完美运行。

但是,如果我,例如希望拥有属于某公司的某种类型的所有文档,无视id和商店,也提供其他公司的文档。

我试过:

query.mapkey_range = [
    ["Vehicle", "", "abc", ""]
    ["Vehicle", q.STRING_RANGE_END, "abc", q.STRING_RANGE_END]
]

我知道,复合键中值的顺序很重要,这就是为什么查询id范围可能是成功的。

但我找不到任何详细的解释,该命令如何重要以及如何处理这个用例。

有任何想法或提示如何应对这个问题? 提前谢谢。

2 个答案:

答案 0 :(得分:1)

使用复合键,emit中的顺序决定内部"排序"的索引。使用范围查询时,将使用此订单。

在你的情况下:

  • 索引包含所有车辆
  • 所有车辆按ID
  • 排序
  • 对于每个类似的ID,车辆按公司分类
  • 对于每个类似的ID和公司,车辆按商店分类

让我们举一个4辆车的例子。这是索引的样子:

Vehicle,a,ACME,store100
Vehicle,c,StackOverflow,store1001
Vehicle,d,ACME,store100
Vehicle,e,StackOverflow,store999

以下是范围查询会发生的情况:

  • 视图引擎在您的范围
  • 中找到第一行> =到startKey
  • 然后找到最后一个< =到你范围的endKey
  • 它返回数组之间的每一行

您可以看到,根据ID,这会导致看似糟糕的结果:对于[["Vehicle", "", "ACME", ""], ["Vehicle", RANGE_END, "ACME", RANGE_END]],会发生以下情况:

  • 第1行(a)被标识为与startKey匹配的最低值
  • 第4行(e与endKey 不匹配,因为"Vehicle,e,StackOverflow,store999"由于第三个组件而大于"Vehicle,RANGE_END,ACME,RANGE_END"
  • 第3行(d是上限Vehicle <= Vehicle, d <= RANGE_END, ACME <= ACME, store100 <= RANGE_END
  • 因此返回第1-3行,包括来自&#34; StackOverflow&#34;
  • 的第2行

TL / DR :在排序事项中排序,您无法使用稀疏&#34; jokers&#34;在复合键的左侧。

将地图功能更改为emit(doc.type, doc.company, doc.store, id)(最常用到最不通用的属性),并且在您相应地重新编写查询后它应该可以正常工作。

以下是解释复合键和日期范围的文档的链接:Partial Selection With Compound Keys

答案 1 :(得分:1)

您可以通过可变数量/字段顺序查询文档有两个选项:

  1. 使用多维视图(又称空间视图),它允许您省略查询中复合键的部分内容。以下是使用此类视图的示例:http://developer.couchbase.com/documentation/server/4.0/views/sv-example2.html
  2. 使用N1QL,它可以让您实际查询任意数量的字段。确保为要查询的字段添加索引,并使用EXPLAIN语句检查查询是否按预期执行。以下是在Python中使用N1QL的方法:http://developer.couchbase.com/documentation/server/4.0/sdks/python-2.0/n1ql-queries.html
  3. 正如您已经发现的那样,您无法使用常规视图,因为您只能按复合键中字段的确切顺序查询。