Mapreduce 如何在RavenDB中进行交叉连接/笛卡尔积?

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

我有一个在后端使用RavenDB的web应用程序,允许用户跟踪库存。我的域中的三个实体是:

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)
                }

    };