3

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

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

结果如下所示:

{
  "ThingId": "Thing/Id26",
  "UserId": null,
  "Longitude": "0",
  "__spatialShape": "0.000000 0.000000"
}

我的模型:

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

关于我做错了什么的任何想法?如果我将组切换到用户,用户部分将被填充并且 ThingId 为空。因此,合并过程似乎失败了。我只是不确定为什么。

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

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

索引本身:

Map:
docs.Things
    .Select(t => new {ThingId = t.__document_id, UserId = (String)null, Latitude = 0, Longitude = 0})

Map:
docs.Users
    .Select(u => new {ThingId = (String)null, UserId = u.__document_id, Latitude = ((double)u.Latitude), Longitude = ((double)u.Longitude)})

Reduce:
results
    .GroupBy(result => result.ThingId)
    .Select(g => new {ThingId = g.Key, UserId = g
    .Select(x => x.UserId)
    .Where(x => x != null).FirstOrDefault(), Latitude = g
    .Select(x => ((double)x.Latitude))
    .Where(t => t != 0).FirstOrDefault(), Longitude = g
    .Select(x => ((double)x.Longitude))
    .Where(t => t != 0).FirstOrDefault()})

生成的投影如下所示:

{
  "ThingId": "Thing/Id26",
  "UserId": null,
  "Latitude": null,
  "Longitude": null
}

我似乎在这里做一些学术上的错误。

4

2 回答 2

0

尝试:

  • 从地图中删除 SpatialIndex.Generate,它应该只在 reduce 上。
  • 从 reduce 中删除 SpatialIndex.Generate 并查看为什么您没有按照应有的纬度和经度。
于 2012-07-13T07:56:55.563 回答
0

通过反复试验(以及 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,
                                                    };
    }
}
于 2012-07-16T10:00:57.677 回答