NEST 中的协变
Convariant search results
version 5.x
NEST 直接支持返回协变结果集合。这意味着,可以将搜索结果的类型指定为一个接口或者基类,但是其真实类型仍然是接口或基类的一个子类型。
让我们来看一个例子,假设我们想要搜索的多个类型都实现了 ISearchResult 接口
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; }
}
使用 Types
要想搜索多个类型,最直接的方式是,先将响应的类型指定为接口或者基类,然后使用 .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> 类型的对象
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);
使用 ConcreteTypeSelector
一个相对较低级别的方式是,自己检查命中结果,并确定要反序列化的 CLR 类型
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);
使用 CovariantTypes
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);
NEST 中的协变的更多相关文章
- 理解Java中的协变返回类型
在面向对象程序设计中,协变返回类型指的是子类中的成员函数的返回值类型不必严格等同于父类中被重写的成员函数的返回值类型,而可以是更 "狭窄" 的类型. Java 5.0添加了对协变返 ...
- c++ 类覆盖方法中的协变返回类型
c++ 类覆盖方法中的协变返回类型 在C++中,只要原来的返回类型是指向类的指针或引用,新的返回类型是指向派生类的指针或引用,覆盖的方法就可以改变返回类型.这样的类型称为协变返回类型(Covarian ...
- Scala中的协变,逆变,上界,下界等
Scala中的协变,逆变,上界,下界等 目录 [−] Java中的协变和逆变 Scala的协变 Scala的逆变 下界lower bounds 上界upper bounds 综合协变,逆变,上界,下界 ...
- 编写高质量代码改善C#程序的157个建议——建议44:理解委托中的协变
建议44:理解委托中的协变 委托中的泛型变量天然是部分支持协变的.为什么是“部分支持协变”?看下面示例: class Program { public delegate T GetEmployeeHa ...
- .net中的协变和逆变
百度:委托中的协变和逆变. 百度:.net中的协变和逆变. 协变是从子类转为父类. 逆变是从父类到子类. 这样理解不一定严谨或者正确.需要具体看代码研究.
- Java泛型中的协变和逆变
Java泛型中的协变和逆变 一般我们看Java泛型好像是不支持协变或逆变的,比如前面提到的List<Object>和List<String>之间是不可变的.但当我们在Java泛 ...
- C#4.0中的协变和逆变
原文地址 谈谈.Net中的协变和逆变 关于协变和逆变要从面向对象继承说起.继承关系是指子类和父类之间的关系:子类从父类继承所以子类的实例也就是父类的实例.比如说Animal是父类,Dog是从Anima ...
- java interface和class中的协变
协变 Java中的协变是指,当发生继承时,子类中重写父类的方法时,可以返回父类方法返回类型的子类型.比如: class SuperClass{} class SubClass extends Supe ...
- C# 中的协变和逆变
作为一个从接触 Unity 3D 才开始学习 C# 的人,我一直只了解一些最基本.最简单的语言特性.最近看了<C# in Depth>这本书,发现这里面东西还真不少,即使除去和 Windo ...
随机推荐
- 自学Python2.1-基本数据类型-字符串str(object)
Python str方法总结 class str(object): """ str(object='') -> str str(bytes_or_buffer[, ...
- js复制链接
需求:js复制一个并非当前页面的链接 实现: html <button class="btn btn-primary btn_copyurl">复制课程链接</b ...
- mysql千万级数据表,创建表及字段扩展的几条建议
一:概述 当我们设计一个系统时,需要考虑到系统的运行一段时间后,表里数据量大约有多少,如果在初期,就能估算到某几张表数据量非常庞大时(比如聊天消息表),就要把表创建好,这篇文章从创建表,增加数据,以及 ...
- Parallels Desktop 12 for Mac 破解版
Parallels Desktop for Mac 是功能最强大灵活度最高的虚拟化方案,无需重启即可在同一台电脑上随时访问Windows和Mac两个系统上的众多应用程序.从仅限于PC的游戏到生产力软件 ...
- go实例之线程池
go语言使用goroutines和channel实现一个工作池相当简单.使用goroutines开指定书目线程,通道分别传递任务和任务结果.简单的线程池代码如下: package main impor ...
- C++各种指针辨析
1)int *p p与*结合,表明p是一个指针 然后前面int说明p是一个整形的指针 2)int *p[n] 因为[]比*优先级高,所以p先与[]结合,表明p是个数组,然后这个数组在与*结合,说明数组 ...
- C++ 头文件系列(stdexcept)
预定义异常类 这个头文件包含的内容非常简单,只包含9个异常类,均从exception类派生,因此我们用三张图来描述: 这里仅解释两点: overflow : 指值的大小超过 整型 变量能表示的范围,即 ...
- lua中易混淆函数
lua中易混淆的函数 ipairs和pairs: ipairs只能顺序遍历table,遇到key不是数字就会退出 pairs可以遍历table中所有元素 ----------------------- ...
- ArcGIS API for JavaScript 4.2学习笔记[10] 2D添加指北针widget、视图保存、视图padding(第二章完结)
这几个例子是第二章除了入门之外比较简单的几个,就做个合集,把最核心的代码(第二参数)和 引用放上来即可,不作多解释. 2D地图添加指北针widget 2D地图一般修正方向为正北方就需要这个widget ...
- MySQL连接方式及大小写问题
一.连接数据库 在命令行连接MySQL有这两种方式,一种是使用命令行参数:另一种是将参数信息写入配置文件 1.命令行中使用参数 -u用户名 -p密码 -D数据库名 -P数据库服务端口 -s安静模式 ...