0

直截了当,我已阅读: http: //www.couchbase.com/docs/couchbase-manual-2.0/couchbase-views-writing-bestpractice.html以及 Couchbase 网站上的其他各种页面,但以下问题仍然困扰着我所以我想在推出之前仔细检查一下。

如果我有关于产品的文档,请说:

"DocumentType": "productDoc",
"Name": "product",
"Price": 150,
"SellerID": 10,
"DeliverableAUWide": true,
"Colour": "red",
"Size": "large"

假设我想要一个介于 100 到 200 之间的产品,那么:

if(doc.DocumentType == "productDoc" && doc.Price)
{
emit([1, doc.Price], null)
}

会得到我想要的开始和结束键

说我也想按尺寸搜索,那么

if(doc.DocumentType == "productDoc" && doc.Size)
{
emit([2, doc.Size], null)
}

会用正确的搜索键再次得到它。

说我想同时搜索两者,然后:

if(doc.DocumentType == "productDoc" && doc.Size && doc.Price)
{
emit([3, doc.Size, doc.Price], null)
}

会得到的。

现在说我要搜索:价格、SellerID、AU 是否可交付、颜色和尺寸....

if(doc.DocumentType == "productDoc" 
&& doc.Price
&& doc.SellerID
&& doc.DeliverableAUWide
&& doc.Colour
&& doc.Size 
)
{
emit([4, doc.Price, doc.SellerID, doc.DeliverableAUWide, doc.Colour, doc.Size], null)
}

会得到的。

但是假设我也希望能够按所有期望价格进行搜索,我不能使用上面的,因为价格将为空,因此其余的发射将是“无用的”,因为一切都会匹配.. .

所以我需要一个新的视图查询?例如

if(doc.DocumentType == "productDoc"

&& doc.SellerID
&& doc.DeliverableAUWide
&& doc.Colour
&& doc.Size 
)
{
emit([5, doc.SellerID, doc.DeliverableAUWide, doc.Colour, doc.Size], null)
}

问题

这种方法是否正确,因为似乎我需要对每种类型的搜索进行“新”发射调用。所以在.net代码中,我会检查我从用户那里得到的搜索输入,然后调用正确的“发射”(注意:这就是为什么我在发射前面有数字,所以我可以稍后将它们区分开来 - - 为了理智...)。

我不仅关心我必须编写的视图的长度,而且说我稍后会在文档中添加一个字段,例如“折扣金额”,然后我更改视图,其重新索引将是巨大的或? 这是关心吗???

上述结构的可能替代方案???

还是最好只说,

if(doc.DocumentType == "productDoc" && doc.Price)
{
emit([1, doc.Price], null)
}
if(doc.DocumentType == "productDoc" && doc.Size)
{
emit([2, doc.Size], null)
}

然后当我想要按价格和尺寸的产品时,调用两者并有效地获取文档 ID 的“列表”,然后“交叉”这些列表并查看两者中都有哪些 ID,然后调用以获取文档。这种方法但是对 CB 服务器的调用要多得多,而且我也无法使用内置的 skip、limit 和 startkey_docid 进行分页。这在代码方面似乎也更加性能密集。我假设这是 Couchbase 的“错误”心态,但来自一个心态是“更少调用 DB = 更好”的环境,我可能没有正确地接受 CB 哲学......

如果有人可以请:

  1. 确认第一种方法是正确的...
  2. 第二个是错的

那很好啊。

如果有什么不明白的地方请告诉我...

提前致谢,

干杯

罗宾

其他注意事项:此文档是存储桶中唯一的文档结构。我只会有 1 个视图。10k 文件 ~ish。

4

3 回答 3

1

对此有一个优雅的解决方案,但请注意,这种方法呈指数级扩展。

您使用复合键走在正确的轨道上。

if(doc.DocumentType == "productDoc" && doc.SellerID && doc.DeliverableAUWide && doc.Colour && doc.Size){
    emit([doc.SellerID, doc.DeliverableAUWide, doc.Colour, doc.Size], null)
}

使您能够过滤所有这些字段。假设您想要所有文档的 SellerId 为 123,DeliverableAUWide 为“true”,颜色为红色,尺寸为 large,只需像这样为查询添加后缀即可。

&startkey[123,"true","red","large"]&endkey[123,"true","red","large",""]

这将返回与这四个验证匹配的所有内容,但您的问题是,如果您使用此视图,则必须为每个类别传递一个值。

该解决方案具有 CouchDB 使用不同键多次发出行的能力。假设您想将颜色保留为通配符,如果您在地图功能中添加新行

if(doc.DocumentType == "productDoc" && doc.SellerID && doc.DeliverableAUWide && doc.Colour && doc.Size){
    emit([doc.SellerID, doc.DeliverableAUWide, doc.Colour, doc.Size], null)
    emit([doc.SellerID, doc.DeliverableAUWide, -1, doc.Size], null)
}

你现在可以像这样查询

&startkey[123,"true",-1,"large"]&endkey[123,"true",-1,"large",""]

(注意:我选择使用 -1 是因为我认为这永远不会是这些字段中的任何一个有效值。任何值都可以工作,只要确保文档上的所有键值实际上都不是您选择的任何值。)

并且包含所有颜色文档的行将返回给您。请注意,您仍然可以使用前面的查询返回同一地图上的所有红色文档。

假设您希望所有过滤器都能够成为通配符。您可以使用以下 map 函数递归地生成您要查找的每个发射。

function(doc, meta) {
  var emitCombos = function(current) {
    var dataSet = [doc.SellerID, doc.DeliverableAUWide, doc.Colour, doc.Size]; //add any new keys as they come up here
    var current = current || [];
    return (current.length === dataSet.length) ? [current] : emitCombos(current.concat(dataSet[current.length])).concat(emitCombos(current.concat(-1)));
  };
  var allCombos = emitCombos();
  //if all three are -1, it's not really filtering, hence the ... .length-1
  for (var combo = 0; combo < allCombos.length - 1; combo++) {
    emit(allCombos[combo].concat(doc.document.createdDate[1]));
  }
}

使用此映射,每个文档将发出带有这些键的行

[ 123, 'TRUE', 'RED', 'LARGE' ]
[ 123, 'TRUE', 'RED', -1 ]
[ 123, 'TRUE', -1, 'LARGE' ]
[ 123, 'TRUE', -1, -1 ]
[ 123, -1, 'RED', 'LARGE' ]
[ 123, -1, 'RED', -1 ]
[ 123, -1, -1, 'LARGE' ]
[ 123, -1, -1, -1 ]
[ -1, 'TRUE', 'RED', 'LARGE' ]
[ -1, 'TRUE', 'RED', -1 ]
[ -1, 'TRUE', -1, 'LARGE' ]
[ -1, 'TRUE', -1, -1 ]
[ -1, -1, 'RED', 'LARGE' ]
[ -1, -1, 'RED', -1 ]
[ -1, -1, -1, 'LARGE' ]

如前所述,您使用的过滤器越多,您发出的行数就越多,从而使您的视图膨胀。所以,请负责任地排放。

于 2015-03-03T01:17:02.713 回答
0

1-使用复合键的第一种方法可能不适合您的要求。我之所以这么说是因为您只能从左到右查询密钥(请参阅http://blog.couchbase.com/understanding-grouplevel-view-queries-compound-keys

2- 进行多次发射的第二种方法是一种可能的方法,但您必须谨慎查询以获取正确的数据范围/类型。正如您所说,如果要添加新属性,则必须重新索引所有文档。

为什么不创建多个视图并采用相同的方法并在您的应用程序中进行相交呢?

另一种方法是使用 Elasticsearch 插件将索引委托给 Elastic 以进行更复杂的全文搜索查询。 http://www.couchbase.com/docs/couchbase-elasticsearch/

PS:视图本身的大小在大多数情况下都不是问题,所以不要担心这一点。

于 2013-04-30T07:33:01.487 回答
0

在 Couchbase 版本 3.x 中,您可以使用N1QL 查询语言来指定过滤条件来选择您的 json 对象,而无需任何视图。

例如,您应该能够发出这样的查询:

SELECT *
  FROM your_bucket_name
    WHERE yourID1 = 'value1' AND yourID2 = 'value2' etc...

试用N1QL 教程

另一种方法是利用Couchbase 与 ElasticSearch 的集成并在 ElasticSearch 引擎中执行搜索查询,该引擎将根据您的搜索条件返回它找到的所有键。它还通过XDCR 流与您的存储桶同步。

于 2014-09-22T16:52:09.143 回答