couchbase 4.0 中的组合键查询
Composite key querying in couchbase 4.0
我看到了这样的景色:
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和store,其他公司的文档也都送了。
我试过:
query.mapkey_range = [
["Vehicle", "", "abc", ""]
["Vehicle", q.STRING_RANGE_END, "abc", q.STRING_RANGE_END]
]
我知道,复合键中值的顺序很重要,这就是查询 id 范围可能成功的原因。
但我找不到任何详细说明订单的重要性以及如何处理此用例。
有什么想法或提示可以解决这个问题吗?
提前谢谢你。
对于复合键,emit
中的顺序决定了索引的内部 "sorting"。使用范围查询时,使用此顺序。
你的情况:
- 索引包含所有车辆
- 然后所有车辆按 id 排序
- 对于每个相似的 id,车辆按公司排序
- 对于每个相似的 ID 和公司,车辆然后按商店排序
我们以4辆车为例。这是索引的样子:
Vehicle,a,ACME,store100
Vehicle,c,Whosebug,store1001
Vehicle,d,ACME,store100
Vehicle,e,Whosebug,store999
这是范围查询发生的情况:
- 视图引擎从您的范围中找到 >= 到 startKey 的第一行
- 然后它会找到 <= 您范围的 endKey 的最后一个
- 它returns 数组中的每一行
您可以看到,根据 ID,这可能会导致看似糟糕的结果:对于 [["Vehicle", "", "ACME", ""], ["Vehicle", RANGE_END, "ACME", RANGE_END]]
,情况如下:
- 第 1 行 (
a
) 被识别为最低匹配 startKey
- 第 4 行 (
e
) 与 endKey 不匹配,因为 "Vehicle,e,Whosebug,store999"
由于第三个组件而大于 "Vehicle,RANGE_END,ACME,RANGE_END"
- 第 3 行(
d
)是上限:Vehicle <= Vehicle, d <= RANGE_END, ACME <= ACME, store100 <= RANGE_END
- 因此返回第 1-3 行,包括来自 "Whosebug"
的第 2 行
TL/DR: emit 中的顺序很重要,不能用复合键左侧的稀疏 "jokers" 进行查询。
将映射函数更改为 emit(doc.type, doc.company, doc.store, id)
(最通用到最不通用的属性),相应地修改查询后它应该可以正常工作。
这是文档中的 link,解释了带日期的复合键和范围:Partial Selection With Compound Keys
您有两个选项可以通过 number/order 个字段的变量查询文档:
- 使用多维视图(又名空间视图),它允许您在查询中省略部分复合键。以下是使用此类视图的示例:http://developer.couchbase.com/documentation/server/4.0/views/sv-example2.html
- 使用 N1QL,它可以让您实际动态查询任意数量的字段。确保为要查询的字段添加索引,并使用 EXPLAIN 语句检查查询是否按预期执行。以下是如何在 Python 中使用 N1QL:http://developer.couchbase.com/documentation/server/4.0/sdks/python-2.0/n1ql-queries.html
正如您已经发现的那样,您不能使用常规视图,因为您只能通过复合键中字段的确切顺序来查询它。
我看到了这样的景色:
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和store,其他公司的文档也都送了。
我试过:
query.mapkey_range = [
["Vehicle", "", "abc", ""]
["Vehicle", q.STRING_RANGE_END, "abc", q.STRING_RANGE_END]
]
我知道,复合键中值的顺序很重要,这就是查询 id 范围可能成功的原因。
但我找不到任何详细说明订单的重要性以及如何处理此用例。
有什么想法或提示可以解决这个问题吗? 提前谢谢你。
对于复合键,emit
中的顺序决定了索引的内部 "sorting"。使用范围查询时,使用此顺序。
你的情况:
- 索引包含所有车辆
- 然后所有车辆按 id 排序
- 对于每个相似的 id,车辆按公司排序
- 对于每个相似的 ID 和公司,车辆然后按商店排序
我们以4辆车为例。这是索引的样子:
Vehicle,a,ACME,store100
Vehicle,c,Whosebug,store1001
Vehicle,d,ACME,store100
Vehicle,e,Whosebug,store999
这是范围查询发生的情况:
- 视图引擎从您的范围中找到 >= 到 startKey 的第一行
- 然后它会找到 <= 您范围的 endKey 的最后一个
- 它returns 数组中的每一行
您可以看到,根据 ID,这可能会导致看似糟糕的结果:对于 [["Vehicle", "", "ACME", ""], ["Vehicle", RANGE_END, "ACME", RANGE_END]]
,情况如下:
- 第 1 行 (
a
) 被识别为最低匹配 startKey - 第 4 行 (
e
) 与 endKey 不匹配,因为"Vehicle,e,Whosebug,store999"
由于第三个组件而大于"Vehicle,RANGE_END,ACME,RANGE_END"
- 第 3 行(
d
)是上限:Vehicle <= Vehicle, d <= RANGE_END, ACME <= ACME, store100 <= RANGE_END
- 因此返回第 1-3 行,包括来自 "Whosebug" 的第 2 行
TL/DR: emit 中的顺序很重要,不能用复合键左侧的稀疏 "jokers" 进行查询。
将映射函数更改为 emit(doc.type, doc.company, doc.store, id)
(最通用到最不通用的属性),相应地修改查询后它应该可以正常工作。
这是文档中的 link,解释了带日期的复合键和范围:Partial Selection With Compound Keys
您有两个选项可以通过 number/order 个字段的变量查询文档:
- 使用多维视图(又名空间视图),它允许您在查询中省略部分复合键。以下是使用此类视图的示例:http://developer.couchbase.com/documentation/server/4.0/views/sv-example2.html
- 使用 N1QL,它可以让您实际动态查询任意数量的字段。确保为要查询的字段添加索引,并使用 EXPLAIN 语句检查查询是否按预期执行。以下是如何在 Python 中使用 N1QL:http://developer.couchbase.com/documentation/server/4.0/sdks/python-2.0/n1ql-queries.html
正如您已经发现的那样,您不能使用常规视图,因为您只能通过复合键中字段的确切顺序来查询它。