【问题标题】:Couchbase Views length - searching on multiple factorsCouchbase Views length - 搜索多个因素
【发布时间】:2013-04-28 07:29:14
【问题描述】:

直截了当,我已阅读: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。

【问题讨论】:

  • CB 视图也缺少的是基于参数的视图...以便调用者可以将一组参数传递给将用于选择过滤器的视图(例如价格限制)跨度>
  • 我不确定你的评论是否理解,你可以在查询时将参数发送到视图;见couchbase.com/docs/couchbase-manual-2.0/…如果这不是你要找的,请告诉我,

标签: couchbase couchbase-view


【解决方案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' ]

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

【讨论】:

    【解决方案2】:

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

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

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

    试试N1QL tutorial

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

    【讨论】:

    • 我最终选择了弹性搜索选项,因为它更加灵活(直到现在)......前几天我确实阅读了这种新的查询语言,它似乎可以解决问题(我做了一个快速测试用例,因为我上面遇到的真正问题很久以前就通过 elasticsearch 解决了)
    【解决方案3】:

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

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

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

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

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

    【讨论】:

    • 这是您的第一点,如果我对 .net 代码很勤奋并且总是有相同的键顺序,那么我认为这应该不是问题吗?我意识到它从左到右,这就是为什么我需要这么多不同的发射和所有可能的搜索组合。重新查看多个视图,是的,我想我可以做到这一点。我想我正试图避开相交,因为那样我就不能使用 B-Tree 来跳过 CB 中的值等。我听说过弹性搜索,但这有什么帮助?我认为这只是真正进行“关键字”搜索,而不是价格、折扣、颜色等......
    • o 而且,顺便说一句,在第一种方法中,重新索引的“成本”会不会比拥有多个视图和多个发射要少?我的意思是我想查询的所有信息都在一个文档中......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-04
    • 2020-07-27
    • 1970-01-01
    相关资源
    最近更新 更多