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,至:
- 防止必须通过正常查询分页,以解决默认页面大小
- 避免在查询时一次加载一个子实体
提前致谢!
尝试使用:
.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
我们目前正在尝试使用 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,至:
- 防止必须通过正常查询分页,以解决默认页面大小
- 避免在查询时一次加载一个子实体
提前致谢!
尝试使用:
.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