Mapreduce 如何在RavenDB中进行交叉连接/笛卡尔积?
我有一个在后端使用RavenDB的web应用程序,允许用户跟踪库存。我的域中的三个实体是:Mapreduce 如何在RavenDB中进行交叉连接/笛卡尔积?,mapreduce,ravendb,Mapreduce,Ravendb,我有一个在后端使用RavenDB的web应用程序,允许用户跟踪库存。我的域中的三个实体是: public class Location { string Id string Name } public class ItemType { string Id string Name } public class Item { string Id DenormalizedRef<Location> Location Denorm
public class Location
{
string Id
string Name
}
public class ItemType
{
string Id
string Name
}
public class Item
{
string Id
DenormalizedRef<Location> Location
DenormalizedRef<ItemType> ItemType
}
这很好,但它只显示项目计数为非零的位置/项目类型对的行。我需要让它显示所有的位置和每个位置,所有的项目类型,甚至那些没有任何项目与之关联
我尝试过几种不同的方法,但到目前为止没有成功。我的想法是将上述内容转换为一个Multi-Map/Reduce索引,然后添加另一个映射,该映射将给出位置和项目类型的笛卡尔乘积,但计数为0。然后我可以将其输入reduce,并始终为每个location/itemtype对创建一个记录
this.AddMap<object>(docs =>
from itemType in docs.WhereEntityIs<ItemType>("ItemTypes")
from location in docs.WhereEntityIs<Location>("Locations")
select new
{
LocationName = location.Name,
ItemTypeName = itemType.Name,
Count = 0
});
以下是如何处理所有空位置的方法:
AddMap<InventoryItem>(inventoryItems =>
from inventoryItem in inventoryItems
select new
{
LocationName = inventoryItem.Location.Name,
Items = new[]{
{
ItemTypeName = inventoryItem.ItemType.Name,
Count = 1}
}
});
)
this.AddMap<Location>(locations=>
from location in locations
select new
{
LocationName = location.Name,
Items = new object[0]
});
this.Reduce = results =>
from result in results
group result by result.LocationName into g
select new
{
LocationName = g.Key,
Items = from item in g.SelectMany(x=>x.Items)
group item by item.ItemTypeName into gi
select new
{
ItemTypeName = gi.Key,
Count = gi.Sum(x=>x.Count)
}
};
AddMap(inventoryItems=>
来自inventoryItems中的inventoryItem
选择新的
{
LocationName=inventoryItem.Location.Name,
项目=新[]{
{
ItemTypeName=inventoryItem.ItemType.Name,
计数=1}
}
});
)
此.AddMap(位置=>
从地点到地点
选择新的
{
LocationName=location.Name,
Items=新对象[0]
});
this.Reduce=结果=>
从结果到结果
按result.LocationName将结果分组到g中
选择新的
{
LocationName=g.键,
Items=来自g.SelectMany中的item(x=>x.Items)
按项分组。ItemTypeName进入gi
选择新的
{
ItemTypeName=gi.Key,
Count=gi.Sum(x=>x.Count)
}
};
问题是,您想要的是所有位置都与所有类型交叉,对吗?问题是,我们可以按位置或类型为您提供,但将它们组合在一起会导致问题。你能先按位置,然后按类型做吗?@AyendeRahien你说得对,我需要所有位置和所有类型交叉。请求是因为最终用户无法看到他们在特定位置“缺货”的项目。我一直在阅读更多关于RavenDB Google Group的文章,看到一些关于Cartesian产品由于“默认安全”心态而没有得到真正支持的言论。在我的例子中,我们讨论了几十个位置,可能有一千种不同的类型,所以索引项的数量并不荒谬。我不知道你所说的“先按地点做,然后按类型做”是什么意思。@DavidArcher我也面临着同样的挑战。你解决过这个问题吗?如果是这样,请您提供最终索引。@FrederikStruck Schøning是的,我通过切换到SQL Server解决了这个问题,因为RavenDB无法满足要求。吸取教训。@DavidArcher-Ouch!我在at面临着同样的问题——离开RavenDB对我们来说不是一个选择,所以我想我可能不得不采取更务实的解决方案。RavenDB毕竟不是一个关系数据库,尽管它可以做一些很酷的事情,但你不能疯狂地加入:)谢谢你回来。我认为这并不能解决我的问题。我编辑了原始问题以添加更明确的示例,但基本上,即使系统中根本没有InventoryItem文档,我也需要有结果。如果用户只是创建了一些位置和项目类型,并且没有输入任何实际的InventoryItems,那么您发布的索引上的第一个映射不会提供任何结果,第二个映射只会为每个位置提供一条记录。
| Location | Item Type | Count |
|----------|-----------|-------|
| London | Desktop | 0 |
| London | Laptop | 0 |
| Paris | Desktop | 0 |
| Paris | Laptop | 0 |
| Berlin | Desktop | 0 |
| Berlin | Laptop | 0 |
AddMap<InventoryItem>(inventoryItems =>
from inventoryItem in inventoryItems
select new
{
LocationName = inventoryItem.Location.Name,
Items = new[]{
{
ItemTypeName = inventoryItem.ItemType.Name,
Count = 1}
}
});
)
this.AddMap<Location>(locations=>
from location in locations
select new
{
LocationName = location.Name,
Items = new object[0]
});
this.Reduce = results =>
from result in results
group result by result.LocationName into g
select new
{
LocationName = g.Key,
Items = from item in g.SelectMany(x=>x.Items)
group item by item.ItemTypeName into gi
select new
{
ItemTypeName = gi.Key,
Count = gi.Sum(x=>x.Count)
}
};