NEST 中的協變

Convariant search results

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, BC對象

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> 類型的對象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);

使用 ConcreteTypeSelector

一個相對較低級別的方式是,本身檢查命中結果,並肯定要反序列化的 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);

使用 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);
相關文章
相關標籤/搜索