【问题标题】:RavenDB - stream index query results in exceptionRavenDB - 流索引查询导致异常
【发布时间】:2015-09-24 18:09:49
【问题描述】:

我们目前正在尝试使用Task<IAsyncEnumerator<StreamResult<T>>> StreamAsync<T>(IQueryable<T> query, CancellationToken token = null),但遇到了一些问题。

我们的文档如下所示:

public class Entity
{
    public string Id { get; set; }

    public DateTime Created { get; set; }

    public Geolocation Geolocation { get; set; }

    public string Description { get; set; }

    public IList<string> SubEntities { get; set; }

    public Entity()
    {
      this.Id = Guid.NewGuid().ToString();
      this.Created = DateTime.UtcNow;
    }
}

结合我们有一个视图模型,这也是模型被索引:

public class EntityViewModel
{
    public string Id { get; set; }

    public DateTime Created { get; set; }

    public Geolocation Geolocation { get; set; }

    public string Description { get; set; }

    public IList<SubEntity> SubEntities { get; set; }
}

当然,索引,其结果类型继承自视图模型,以使子实体能够正确映射和输出,同时支持添加全文等搜索功能:

public class EntityWithSubentitiesIndex : AbstractIndexCreationTask<Entity, EntityWithSubentitiesIndex.Result>
{
    public class Result : EntityViewModel
    {
         public string Fulltext { get; set; }
    }

    public EntityWithSubentitiesIndex ()
    {
        Map = entities => from entity in entities
                select new
                {
                    Id = entity.Id,
                    Created = entity.Created,
                    Geolocation = entity.Geolocation,
                    SubEntities = entity.SubEntities.Select(x => LoadDocument<SubEntity>(x)),
                    Fulltext = new[]
                    {
                        entity.Description
                    }.Concat(entity.SubEntities.Select(x => LoadDocument<SubEntity>(x).Name)),
                    __ = SpatialGenerate("__geolokation", entity.Geolocation.Lat, entity.Geolocation.Lon)
                };

            Index(x => x.Created.Date, FieldIndexing.Analyzed);
            Index(x => x.Fulltext, FieldIndexing.Analyzed);
            Spatial("__geolokation", x => x.Cartesian.BoundingBoxIndex());
        }
}

最后我们这样查询:

var query = _ravenSession.Query<EntityWithSubentitiesIndex.Result, EntityWithSubentitiesIndex>()
                .Customize(c =>
                {
                    if (filter.Boundary == null) return;

                    var wkt = filter.Boundary.GenerateWkt().Result;
                    if (!string.IsNullOrWhiteSpace(wkt))
                    {
                        c.RelatesToShape("__geolokation", wkt, SpatialRelation.Within);
                    }
                })
                .AsQueryable();

// (...) and several other filters here, removed for clarity

var enumerator = await _ravenSession.Advanced.StreamAsync(query);

var list = new List<EntityViewModel>(); 
while (await enumerator.MoveNextAsync())
{
    list.Add(enumerator.Current.Document);
}

这样做时,我们会收到以下异常:

System.InvalidOperationException:查询结果类型为“实体” 但您希望得到“结果”类型的结果。如果你想 返回一个投影,你应该使用 .ProjectFromIndexFieldsInto()(用于查询)或 .SelectFields()(用于 DocumentQuery)在调用之前 .ToList()。

根据文档,Streaming API 应该支持通过索引进行流式传输,并同时通过 IQueryable 进行查询。

如何在仍然使用索引和流式 API 的情况下解决此问题:

  1. 避免必须通过正常查询分页来解决默认页面大小
  2. 避免在查询时一次加载一个子实体

提前致谢!

【问题讨论】:

    标签: c# .net ravendb


    【解决方案1】:

    尝试使用:

    .As<Entity>()
    

    (或.OfType&lt;Entity&gt;())在您的查询中。这应该在常规流中有效。

    这是一个使用“TestIndex”的简单流式查询,它是实体Test 的索引,我使用TestIndex.Result 看起来像您的查询。 请注意,这实际上不是查询将返回的内容,它只是在那里您可以编写类型化查询(即.Where(x =&gt; x.SomethingMapped == something)

    var queryable = session.Query<TestIndex.Result, TestIndex>()
                            .Customize(c =>
                            {
                                //do stuff
                            })
                            .As<Test>();
    
    var enumerator = session.Advanced.Stream(queryable);
    
    while (enumerator.MoveNext())
    {
        var entity = enumerator.Current.Document;
    }
    

    如果您想从 index 中检索值而不是被索引的实际实体,则必须将它们存储为字段,然后将它们投影到与您的映射属性匹配的“视图模型”中.这可以通过在查询中使用 .ProjectFromIndexFieldsInto&lt;T&gt;() 来完成。索引中的所有存储字段都将映射到您指定的模型。

    希望这会有所帮助(并且有意义)!

    编辑:对我来说,更新了与ProjectFromIndexFieldsInto&lt;T&gt;() 一起使用的 Streaming API 的工作示例,该示例返回超过 128 条记录。

    using (var session = store.OpenAsyncSession())
    {
        var queryable = session.Query<Customers_ByName.QueryModel, Customers_ByName>()
            .Customize(c =>
            {
                //just to do some customization to look more like OP's query
                c.RandomOrdering();
            })
            .ProjectFromIndexFieldsInto<CustomerViewModel>();
    
        var enumerator = await session.Advanced.StreamAsync(queryable);
    
        var customerViewModels = new List<CustomerViewModel>();
        while (await enumerator.MoveNextAsync())
        {
            customerViewModels.Add(enumerator.Current.Document);
        }
    
        Console.WriteLine(customerViewModels.Count); //in my case 504
    }
    

    上面的代码很适合我。该索引具有一个映射的属性(名称)并且该属性被存储。这是运行最新的稳定版本 (3.0.3800)。

    【讨论】:

    • 您好,感谢您的回答。我们在使用正常的分页查询时使用ProjectFromIndexFieldsInto&lt;T&gt;(),它完美无缺。问题是,当我将 ProjectFromIndexFieldsInto&lt;T&gt;() 与 Streaming API 结合使用时,由于某种原因,它又回到了绑定到 128 个结果的状态。
    • @JackieNagel 很奇怪。我已经更新了我的答案,该查询将 Streaming API 与 ProjectFromIndexFieldsInto&lt;T&gt;() 结合使用,并返回超过 128 个结果...
    • 确实很奇怪。非常感谢您的输入,但不幸的是,这些都不起作用,仍然最多接收 128 个文档。我有预感它可能是RavenDB版本,但是在服务器和客户端升级之后它仍然是一样的。我必须深入挖掘。
    • 似乎它在对 Raven 的请求上设置了 128 的页面大小,这很不幸,但解释了为什么它不起作用:-/
    • 看来128的pagesize是c.RelatesToShape()调用引入的。使用上面示例中的 c.RandomOrdering(),它返回超过 128 个结果。使用 RelatesToShape 它只返回 128。
    【解决方案2】:

    正如 @nicolai-heilbuth 在 cmets 中对 @jens-pettersson 的回答所述,这似乎是 RavenDB 客户端库从版本 3 开始的一个错误。

    在此处提交的错误报告:http://issues.hibernatingrhinos.com/issue/RavenDB-3916

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-09
      • 2018-01-14
      • 1970-01-01
      • 2013-08-23
      相关资源
      最近更新 更多