Mapreduce RavenDB中带空间索引的多地图索引失败

Mapreduce RavenDB中带空间索引的多地图索引失败,mapreduce,ravendb,Mapreduce,Ravendb,我想搜索属于用户的东西(在我附近)。我已定义了以下索引,但未获得合并结果集: public class Things_ByLocation : AbstractMultiMapIndexCreationTask<Things_ByLocation.ThingsByLocationResult> { public class ThingsByLocationResult { public string ThingId { get; set; }

我想搜索属于用户的东西(在我附近)。我已定义了以下索引,但未获得合并结果集:

public class Things_ByLocation : AbstractMultiMapIndexCreationTask<Things_ByLocation.ThingsByLocationResult>
{
    public class ThingsByLocationResult
    {
        public string ThingId { get; set; }
        public string UserId { get; set; }
        public double Latitude { get; set; }
        public double Longitude { get; set; }
    }

    public Things_ByLocation()
    {
        AddMap<Thing>(things => from t in things
                                select new
                                {
                                    ThingId = t.Id,
                                    UserId = (string)null,
                                    Latitude = 0,
                                    Longitude = 0,
                                    _ = (object)null,
                                });
        AddMap<User>(users => from u in users
                                select new
                                {
                                    ThingId = (string)null,
                                    UserId = u.Id,
                                    Latitude = u.Latitude,
                                    Longitude = u.Longitude,
                                    _ = SpatialIndex.Generate(u.Latitude, u.Longitude)
                                });

        Reduce = results => from result in results
                            group result by result.ThingId into g
                            let userId = g.Select(x => x.UserId).Where(t => !string.IsNullOrWhiteSpace(t)).FirstOrDefault()
                            let lat = g.Select(x => x.Latitude).Where(t => t != 0).FirstOrDefault()
                            let lng = g.Select(x => x.Longitude).Where(t => t != 0).FirstOrDefault()
                            select new
                            {
                                ThingId = g.Key,
                                UserId = userId,
                                Latitude = lat,
                                Longitude = lng,
                                _ = SpatialIndex.Generate(lat, lng)
                            };

        Store(x => x.ThingId, FieldStorage.Yes);
        Store(x => x.UserId, FieldStorage.Yes);
    }
}
我的模型:

public class User
{
    public string Id { get; set; }
    public double Latitude { get; set; }
    public double Longitude { get; set; }
}

public class Thing
{
    public string Id { get; set; }
    public double Name { get; set; }
    public double Description { get; set; }
    public string UserId { get; set; }
}
你知道我做错了什么吗?如果我将组切换到用户,则会填充user部分,ThingId为null。因此,合并过程似乎失败了。我只是不知道为什么

这也很奇怪,为什么结果显示的是经度,而不是纬度属性

在RAM中使用RavenDB Build 960

我意识到我可以将位置反规范化为东西,但这意味着如果用户位置改变,我将不得不更新数百件东西。这是首选的NoSql方式吗

更新

根据Ayende的建议,我现在有以下几点:

public class Things_ByLocation : AbstractMultiMapIndexCreationTask<Things_ByLocation.ThingsByLocationResult>
{
    public class ThingsByLocationResult
    {
        public string ThingId { get; set; }
        public string UserId { get; set; }
        public double Latitude { get; set; }
        public double Longitude { get; set; }
    }

    public Things_ByLocation()
    {
        AddMap<Thing>(things => from t in things
                                select new
                                {
                                    ThingId = t.Id,
                                    UserId = (string)null,
                                    Latitude = 0,
                                    Longitude = 0
                                });
        AddMap<User>(users => from u in users
                                select new
                                {
                                    ThingId = (string)null,
                                    UserId = u.Id,
                                    Latitude = u.Latitude,
                                    Longitude = u.Longitude
                                });

        Reduce = results => from result in results
                            group result by result.ThingId into g
                            select new
                            {
                                ThingId = g.Key,
                                UserId = g.Select(x => x.UserId).Where(x => x != null).FirstOrDefault(),
                                Latitude = g.Select(x => x.Latitude).Where(t => t != 0).FirstOrDefault(),
                                Longitude = g.Select(x => x.Longitude).Where(t => t != 0).FirstOrDefault()
                            };

        Store(x => x.ThingId, FieldStorage.Yes);
        Store(x => x.UserId, FieldStorage.Yes);
    }
}
生成的投影如下所示:

{
  "ThingId": "Thing/Id26",
  "UserId": null,
  "Longitude": "0",
  "__spatialShape": "0.000000 0.000000"
}
{
  "ThingId": "Thing/Id26",
  "UserId": null,
  "Latitude": null,
  "Longitude": null
}
我在这里似乎做了一些学术上的错误。

试试:

  • 从地图中删除SpatialIndex.Generate时,它应仅位于reduce上
  • 从reduce中删除SpatialIndex.Generate,然后看看为什么不按您应该的方式计算纬度和经度

经过反复试验(以及Ayende的建议),我得出以下结论。它是有效的,但我不知道为什么

我怀疑我最好改变数据模型,并将地理位置数据反规范化

public class Things_ByLocation : AbstractMultiMapIndexCreationTask<Things_ByLocation.ThingsByLocationResult>
{
    public class ThingsByLocationResult
    {
        public string Id { get; set; }
        public string UserId { get; set; }
        public double Latitude { get; set; }
        public double Longitude { get; set; }
        public string SKU { get; set; }
        public string Name { get; set; }
    }

    public Things_ByLocation()
    {
        AddMap<Thing>(things => from t in things
                                select new
                                {
                                    Id = t.Id,
                                    UserId = t.UserId,
                                    Latitude = 0,
                                    Longitude = 0,
                                    Name = t.Name,
                                    SKU = t.SKU,
                                    _ = (object)null,
                                });
        AddMap<User>(users => from u in users
                                select new
                                {
                                    Id = (string)null,
                                    UserId = u.Id,
                                    Latitude = u.Latitude,
                                    Longitude = u.Longitude,
                                    Name = (string)null,
                                    SKU = (string)null,
                                    _ = (object)null, 
                                });

        Reduce = results => from result in results
                            group result by result.Id into g
                            let lat = g.Select(x => x.Latitude).Where(x => x != 0).FirstOrDefault()
                            let lng = g.Select(x => x.Longitude).Where(x => x != 0).FirstOrDefault()
                            let userId = g.Select(x => x.UserId).Where(x => x != null).FirstOrDefault()
                            let name = g.Select(x => x.Name).Where(x => x != null).FirstOrDefault()
                            let sku = g.Select(x => x.SKU).Where(x => x != null).FirstOrDefault()
                            select new
                            {
                                Id = g.Key,
                                UserId = userId,
                                Latitude = lat,
                                Longitude = lng,
                                Name = name,
                                SKU = sku,
                                _ = SpatialIndex.Generate(lat, lng)
                            };

        Store(x => x.Id, FieldStorage.Yes);
        Store(x => x.UserId, FieldStorage.Yes);

        TransformResults = (database, results) => from result in results
                                                    let user = database.Load<User>(result.UserId)
                                                    select new
                                                    {
                                                        Id = result.Id,
                                                        UserId = result.UserId,
                                                        Latitude = user.Latitude,
                                                        Longitude = user.Longitude,
                                                        Name = result.Name,
                                                        SKU = result.SKU,
                                                    };
    }
}
public class Things\u ByLocation:AbstractMultiMapIndexCreationTask
{
公共类ThingsByLocationResult
{
公共字符串Id{get;set;}
公共字符串用户标识{get;set;}
公共双纬度{get;set;}
公共双经度{get;set;}
公共字符串SKU{get;set;}
公共字符串名称{get;set;}
}
公共事务
{
AddMap(things=>来自things中的t
选择新的
{
Id=t.Id,
UserId=t.UserId,
纬度=0,
经度=0,
Name=t.Name,
SKU=t.SKU,
_=(对象)空,
});
AddMap(用户=>来自用户中的u
选择新的
{
Id=(字符串)null,
UserId=u.Id,
纬度=美国纬度,
经度=美国经度,
Name=(字符串)null,
SKU=(字符串)null,
_=(对象)空,
});
Reduce=results=>from result in results
按result.Id将结果分组到g中
让lat=g.Select(x=>x.Latitude)。其中(x=>x!=0)。FirstOrDefault()
让lng=g.Select(x=>x.Longitude)。其中(x=>x!=0)。FirstOrDefault()
让userId=g.Select(x=>x.userId)。其中(x=>x!=null)。FirstOrDefault()
让name=g.Select(x=>x.name)。其中(x=>x!=null)。FirstOrDefault()
让sku=g.Select(x=>x.sku)。其中(x=>x!=null)。FirstOrDefault()
选择新的
{
Id=g.键,
UserId=UserId,
纬度=纬度,
经度=液化天然气,
Name=Name,
SKU=SKU,
_=空间索引生成(纬度,液化天然气)
};
存储(x=>x.Id,FieldStorage.Yes);
存储(x=>x.UserId,FieldStorage.Yes);
TransformResults=(数据库,结果)=>来自结果中的结果
让user=database.Load(result.UserId)
选择新的
{
Id=result.Id,
UserId=result.UserId,
纬度=用户。纬度,
经度=用户。经度,
Name=result.Name,
SKU=result.SKU,
};
}
}

我已经试过了,并且更新了我原来的问题。还是一个类似的问题。有什么建议吗?
public class Things_ByLocation : AbstractMultiMapIndexCreationTask<Things_ByLocation.ThingsByLocationResult>
{
    public class ThingsByLocationResult
    {
        public string Id { get; set; }
        public string UserId { get; set; }
        public double Latitude { get; set; }
        public double Longitude { get; set; }
        public string SKU { get; set; }
        public string Name { get; set; }
    }

    public Things_ByLocation()
    {
        AddMap<Thing>(things => from t in things
                                select new
                                {
                                    Id = t.Id,
                                    UserId = t.UserId,
                                    Latitude = 0,
                                    Longitude = 0,
                                    Name = t.Name,
                                    SKU = t.SKU,
                                    _ = (object)null,
                                });
        AddMap<User>(users => from u in users
                                select new
                                {
                                    Id = (string)null,
                                    UserId = u.Id,
                                    Latitude = u.Latitude,
                                    Longitude = u.Longitude,
                                    Name = (string)null,
                                    SKU = (string)null,
                                    _ = (object)null, 
                                });

        Reduce = results => from result in results
                            group result by result.Id into g
                            let lat = g.Select(x => x.Latitude).Where(x => x != 0).FirstOrDefault()
                            let lng = g.Select(x => x.Longitude).Where(x => x != 0).FirstOrDefault()
                            let userId = g.Select(x => x.UserId).Where(x => x != null).FirstOrDefault()
                            let name = g.Select(x => x.Name).Where(x => x != null).FirstOrDefault()
                            let sku = g.Select(x => x.SKU).Where(x => x != null).FirstOrDefault()
                            select new
                            {
                                Id = g.Key,
                                UserId = userId,
                                Latitude = lat,
                                Longitude = lng,
                                Name = name,
                                SKU = sku,
                                _ = SpatialIndex.Generate(lat, lng)
                            };

        Store(x => x.Id, FieldStorage.Yes);
        Store(x => x.UserId, FieldStorage.Yes);

        TransformResults = (database, results) => from result in results
                                                    let user = database.Load<User>(result.UserId)
                                                    select new
                                                    {
                                                        Id = result.Id,
                                                        UserId = result.UserId,
                                                        Latitude = user.Latitude,
                                                        Longitude = user.Longitude,
                                                        Name = result.Name,
                                                        SKU = result.SKU,
                                                    };
    }
}