version 5.xc#
NEST 直接支持返回协变结果集合。这意味着,能够将搜索结果的类型指定为一个接口或者基类,可是其真实类型仍然是接口或基类的一个子类型。this
让咱们来看一个例子,假设咱们想要搜索的多个类型都实现了 ISearchResult
接口code
public interface ISearchResult { string Name { get; set; } } public abstract class BaseX : ISearchResult { public string Name { get; set; } }
针对 ISearchResult
,咱们提供了三种实现,分别叫 A
, B
和 C
对象
public class A : BaseX { public int PropertyOnA { get; set; } } public class B : BaseX { public int PropertyOnB { get; set; } } public class C : BaseX { public int PropertyOnC { get; set; } }
要想搜索多个类型,最直接的方式是,先将响应的类型指定为接口或者基类,而后使用 .Type()
传递咱们想搜索的实际类型接口
var result = this._client.Search<ISearchResult>(s => s .Type(Types.Type(typeof(A), typeof(B), typeof(C))) .Size(100) );
NEST 会把这份逻辑代码转化为 /index/a,b,c/_search
,有 "_type" : "a"
的命中结果会被序列化为 A
类型的对象,以此类推。文档
在这里,咱们假设全部的响应都是有效的,而且咱们将接收到预期的 100 份文档。记住, result.Document
是一个 IReadOnlyCollection<ISearchResult>
类型的对象get
result.ShouldBeValid(); result.Documents.Count.Should().Be(100);
为了证实返回的结果集合是协变的,咱们根据它们的真实类型过滤文档,并断言这些子集是咱们指望的大小string
var aDocuments = result.Documents.OfType<A>(); var bDocuments = result.Documents.OfType<B>(); var cDocuments = result.Documents.OfType<C>(); aDocuments.Count().Should().Be(25); bDocuments.Count().Should().Be(25); cDocuments.Count().Should().Be(50);
另外,假设只存在于子类自己的属性会被正确填充it
aDocuments.Should().OnlyContain(a => a.PropertyOnA > 0); bDocuments.Should().OnlyContain(a => a.PropertyOnB > 0); cDocuments.Should().OnlyContain(a => a.PropertyOnC > 0);
一个相对较低级别的方式是,本身检查命中结果,并肯定要反序列化的 CLR 类型io
var result = this._client.Search<ISearchResult>(s => s .ConcreteTypeSelector((d, h) => h.Type == "a" ? typeof(A) : h.Type == "b" ? typeof(B) : typeof(C)) .Size(100) );
对于每个命中结果,咱们会调用传递给 ConcreteTypeSelector
的委托
d
表示 _source
公开为一个 dynamic
类型h
表明着对命中结果的封装(例如:Hit<dynamic>
)咱们假设响应是有效的,而且接收到了预期的 100 份文档。记住, result.Document
是一个 IReadOnlyCollection<ISearchResult>
类型的对象
result.ShouldBeValid(); result.Documents.Count.Should().Be(100);
为了证实返回的结果集合是协变的,咱们根据它们的真实类型过滤文档,并断言这些子集是咱们指望的大小
var aDocuments = result.Documents.OfType<A>(); var bDocuments = result.Documents.OfType<B>(); var cDocuments = result.Documents.OfType<C>(); aDocuments.Count().Should().Be(25); bDocuments.Count().Should().Be(25); cDocuments.Count().Should().Be(50);
另外,假设只存在于子类自己的属性会被正确填充
aDocuments.Should().OnlyContain(a => a.PropertyOnA > 0); bDocuments.Should().OnlyContain(a => a.PropertyOnB > 0); cDocuments.Should().OnlyContain(a => a.PropertyOnC > 0);
Scroll API 是上一个搜索示例的延伸,咱们再也不使用 Types() 。你可使用 .CovariantTypes()
来指示类型。
var result = this._client.Scroll<ISearchResult>(TimeSpan.FromMinutes(60), "scrollId", s => s .CovariantTypes(Types.Type(typeof(A), typeof(B), typeof(C))) );
NEST 会把这份逻辑代码转化为 /index/a,b,c/_search
,有 "_type" : "a"
的命中结果会被序列化为 A
类型的对象,以此类推。
后续的验证过程同上(也许你已经发现前面的两节内容里存在者相同的步骤)
相对较低级别的 concrete type selector 也能够用在 scroll 中
var result = this._client.Scroll<ISearchResult>(TimeSpan.FromMinutes(1), "scrollid", s => s .ConcreteTypeSelector((d, h) => h.Type == "a" ? typeof(A) : h.Type == "b" ? typeof(B) : typeof(C)) );
重复验证工做
协变不单单在接口方式中工做,下面即是子类型协变的示例:
var result = this._client.Search<BaseX>(s => s .Type(Types.Type(typeof(A), typeof(B), typeof(C))) .Size(100) ); result.ShouldBeValid(); result.Documents.Count.Should().Be(100); var aDocuments = result.Documents.OfType<A>(); var bDocuments = result.Documents.OfType<B>(); var cDocuments = result.Documents.OfType<C>(); aDocuments.Count().Should().Be(25); bDocuments.Count().Should().Be(25); cDocuments.Count().Should().Be(50); aDocuments.Should().OnlyContain(a => a.PropertyOnA > 0); bDocuments.Should().OnlyContain(a => a.PropertyOnB > 0); cDocuments.Should().OnlyContain(a => a.PropertyOnC > 0);