RavenDB - 流索引查询结果异常

RavenDB - stream index query results in exception

我们目前正在尝试使用 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: The query results type is 'Entity' but you expected to get results of type 'Result'. If you want to return a projection, you should use .ProjectFromIndexFieldsInto() (for Query) or .SelectFields() (for DocumentQuery) before calling to .ToList().

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

如何解决这个问题,同时仍然使用索引和流 API,至:

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

提前致谢!

尝试使用:

.As<Entity>()

(或 .OfType<Entity>())在您的查询中。这应该适用于常规流。

这是一个使用 "TestIndex" 的简单流式查询,它是实体 Test 的索引,我使用 TestIndex.Result 来看起来像您的查询。 请注意,这实际上不是查询 return 的内容,它只是为了让您可以编写类型化查询(即 .Where(x => 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 中检索值而不是被索引的实际实体,则必须将它们存储为字段,然后将它们投影到 "view model" 匹配您的映射属性。这可以通过在查询中使用 .ProjectFromIndexFieldsInto<T>() 来完成。索引中的所有存储字段都将映射到您指定的模型。

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

编辑:更新了一个,对我来说,与 ProjectFromIndexFieldsInto<T>() 一起使用的 Streaming API 的工作示例 return 超过 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)。

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

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