2016-04-22 52 views
0

我有2種類型的一個指數,都具有推薦領域(如需要)Elasticsearch建議是合併兩種

public class LegalAreaSearchModel : LegalAreaModel 
{ 
    public SuggestField Suggest 
    { 
     get 
     { 
      List<string> input = new List<string>(); 
      string[] childArea = !string.IsNullOrEmpty(this.LegalArea) ? this.LegalArea.Split(' ') : new string[] { "" }; 
      string[] ParentArea = !string.IsNullOrEmpty(this.Parent) ? this.Parent.Split(' ') : new string[] { "" }; 
      input.AddRange(childArea); 
      input.AddRange(ParentArea); 
      return 

       new SuggestField 
       { 
        Input = input, 
        Output = this.LegalArea, 
        Payload = new 
        { 
         Id = this.RowId, 
         Name = !string.IsNullOrEmpty(this.Parent) ? this.Parent + "/" + this.LegalArea : this.LegalArea, 
         Type = "Specialization" 
        }, 
        Weight = !string.IsNullOrEmpty(this.LegalArea) ? this.LegalArea.Length : 0 
       }; 

     } 
    } 
} 

public class LegalDocumentSearchModel : LegalDocumentModel 
{ 


    public LegalDocumentSearchModel() 
    { 
     //this = ObjectCopier.Clone<LegalDocumentSearchModel>(legalDocumentSearchModel); 
     SupplierDetails = new List<LegalDocumentSupplierDetailForSearch>(); 
     CategoryDetails = new List<CategoryDetails>(); 

    } 

    [Nested()] 
    public List<LegalDocumentSupplierDetailForSearch> SupplierDetails { get; set; } 

    [Nested()] 
    public List<CategoryDetails> CategoryDetails { get; set; } 

    public SuggestField Suggest 
    { 
     get 
     { 
      return 
        new SuggestField 
        { 
         Input = new List<string>(!string.IsNullOrEmpty(this.Name) ? this.Name.Split(' ') : new string[] { "" }) { this.Name }, 
         Output = this.Name, 
         Payload = new 
         { 
          Id = this.RowId, 
          SEOFriendlyURLName = !string.IsNullOrEmpty(this.SEOFriendlyURLName) ? string.Concat(this.SEOFriendlyURLName) : string.Empty, 
          Name = this.Name, 
          ProductType = this.ProductType, 
          Description = this.Description 

         }, 
         Weight = !string.IsNullOrEmpty(this.Description) ? this.Description.Length : 0 
        }; 
     } 
    } 

} 
public class LegalDocumentSupplierDetailForSearch 
{ 
    public string PinCode { get; set; } 
    public string Lattitude { get; set; } 
    public string Longitude { get; set; } 

} 
public class CategoryDetails 
{ 
    public int CategoryId { get; set; } 
    public string CategoryName { get; set; } 
} 

現在的結果我的搜索如下

List<AdvocateListingSuggestionModel> lsResult = new List<AdvocateListingSuggestionModel>(); 
     var result = _searchProvider.Client.Suggest<LegalAreaSearchModel>(s => s 
               .Index(SearchConfigurationManager.DefaultSearchIndex) 
               .Completion("ml-la-suggestions", c => c 
               .Text(Search) 
               .Field(p => p.Suggest) 
               .Fuzzy(fz => fz 
                .Fuzziness(Fuzziness.Auto)) 
               ) 
      ); 

我從其他類型也得到結果(混合)我們如何限制只有一種類型的結果

Type1.LegalAreaSearchModel 類型2.LegalDocumentSearchModel

我的索引是如下

public static bool CheckForIndex(ElasticSearchProvider searchProvider) 
    { 

     Nest.IndexExistsRequest idr = new Nest.IndexExistsRequest(Nest.Indices.Index(new Nest.IndexName() { Name = SearchConfigurationManager.DefaultSearchIndex })); 
     var indxres = searchProvider.Client.IndexExists(idr); 

     if (!indxres.Exists) 
     { 
      searchProvider.Client.CreateIndex(SearchConfigurationManager.DefaultSearchIndex, i => i 
      .Settings(s => s 
       .NumberOfShards(2) 
       .NumberOfReplicas(0) 
       .Analysis(analysis => analysis 
        .Tokenizers(tokenizers => tokenizers 
         .Pattern("ml-id-tokenizer", p => p.Pattern(@"\W+")) 
        ) 
        .TokenFilters(tokenfilters => tokenfilters 
         .WordDelimiter("ml-id-words", wd => wd 
          .SplitOnCaseChange() 
          .PreserveOriginal() 
          .SplitOnNumerics() 
          .GenerateNumberParts(false) 
          .GenerateWordParts() 
         ) 
        ) 
        .Analyzers(analyzers => analyzers 
         .Custom("ml-id-analyzer", c => c 
          .Tokenizer("ml-id-tokenizer") 
          .Filters("ml-id-words", "lowercase") 
         ) 
         .Custom("ml-id-keyword", c => c 
          .Tokenizer("keyword") 
          .Filters("lowercase") 
         ) 
        ) 
       ) 
      )); 
     } 
     return true; 
    } 

Creatining文件類型如下

public bool CreateDocumentIndex() 
    { 
     bool retVal = false; 
     if (Common.CheckForIndex(_searchProvider)) 
     { 
      var res = _searchProvider.Client.Map<LegalDocumentSearchModel>(m => 
                    m.Index(SearchConfigurationManager.DefaultSearchIndex) 
                    .Type(this.type) 
                    .AutoMap() 
                    .Properties(ps => ps 
                    .String(s => s 
                      .Name(p => p.Id) 
                      .Analyzer("ml-id-analyzer") 
                       .Fields(f => f 
                        .String(p => p.Name("keyword").Analyzer("ml-id-keyword")) 
                        .String(p => p.Name("raw").Index(FieldIndexOption.NotAnalyzed)) 
                      ) 
                    ) 
                    .Completion(c => c 
                      .Name(p => p.Suggest) 
                      .Payloads() 
                    ) 
                    )); 

      retVal = res.IsValid; 


     } 
     return retVal; 
    } 

創建LegalArea類型如下

public bool CreateLegalAreaIndex() 
    { 
     bool retVal = false; 
     if (Common.CheckForIndex(_searchProvider)) 
     { 
      var res = _searchProvider.Client.Map<LegalAreaSearchModel>(m => 
                    m.Index(SearchConfigurationManager.DefaultSearchIndex) 
                    .Type(this.type) 
                    .AutoMap() 
                    .Properties(ps => ps 
                    .String(s => s 
                      .Name(p => p.Id) 
                      .Analyzer("ml-id-analyzer") 
                       .Fields(f => f 
                        .String(p => p.Name("keyword").Analyzer("ml-id-keyword")) 
                        .String(p => p.Name("raw").Index(FieldIndexOption.NotAnalyzed)) 
                       ) 
                     ) 
                    .Completion(c => c 
                      .Name(p => p.Suggest) 
                      .Payloads() 
                     ) 
                    )); 

      retVal = res.IsValid; 
     } 
     return retVal; 
    } 

現在,當我運行的法律領域的建議如下

public List<AdvocateListingSuggestionModel> LegalAreaSuggestion(string Search) 
    { 
     List<AdvocateListingSuggestionModel> lsResult = new List<AdvocateListingSuggestionModel>(); 
     var result = _searchProvider.Client.Suggest<LegalAreaSearchModel>(s => s 
               .Index(SearchConfigurationManager.DefaultSearchIndex) 
               .Completion("ml-la-suggestions", c => c 
               .Text(Search) 
               .Field(p => p.Suggest) 
               .Fuzzy(fz => fz 
                .Fuzziness(Fuzziness.Auto)) 
               ) 
      ); 
     if (result.IsValid) 
     { 
      lsResult = result.Suggestions["ml-la-suggestions"] 
        .FirstOrDefault() 
        .Options 
        .Select(suggest => suggest.Payload<AdvocateListingSuggestionModel>()).ToList(); 
     } 
     return lsResult; 
    } 

我得到LegalDocumentSearchModel的結果well.pls建議

感謝

+1

什麼您使用的是NEST版本,您使用的是哪種版本的Elasticsearch? –

+0

Nest 2.1.0和Elasticsearch 2.3 –

+0

@RussCam任何解決方案? –

回答

0

Suggesters在指數層面的工作,也就是說, one Finite State Transducer (FST) is created for a field per index因此,如果在同一索引中有兩個具有相同字段名稱的類型(兩個字段必須必須是相同類型),則兩種類型的數據都將在一個FST中表示。

我們可以看一個簡單的例子。在這裏,我們有兩種類型的完成字段,我們要索引相同的索引

public class Band 
{ 
    public int Id { get; set;} 

    public CompletionField<object> Suggest { get; set;} 
} 

public class Sport 
{ 
    public int Id { get; set;} 

    public CompletionField<object> Suggest { get; set; } 
} 

void Main() 
{ 
    var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200")); 
    var defaultIndex = "default-index"; 
    var connectionSettings = new ConnectionSettings(pool) 
      .DefaultIndex(defaultIndex); 

    var client = new ElasticClient(connectionSettings); 

    // just so we can re-run this example... 
    if (client.IndexExists(defaultIndex).Exists) 
     client.DeleteIndex(defaultIndex); 

    client.CreateIndex(defaultIndex, ci => ci 
     .Mappings(m => m 
      .Map<Band>(l => l 
       .AutoMap() 
       .Properties(p => p 
        .Completion(c => c 
         .Name(n => n.Suggest) 
        ) 
       ) 
      ) 
      .Map<Sport>(l => l 
       .AutoMap() 
       .Properties(p => p 
        .Completion(c => c 
         .Name(n => n.Suggest) 
        ) 
       ) 
      ) 
     ) 
    ); 

    var bands = new List<Band> 
    { 
     new Band { Id = 1, Suggest = new CompletionField<object> { Input = new [] {"Bowling for Soup"} } }, 
     new Band { Id = 2, Suggest = new CompletionField<object> { Input = new [] {"Fastball"} } }, 
     new Band { Id = 3, Suggest = new CompletionField<object> { Input = new [] {"Dropkick Murphys"} } }, 
     new Band { Id = 4, Suggest = new CompletionField<object> { Input = new [] {"Yellowcard"} } }, 
     new Band { Id = 5, Suggest = new CompletionField<object> { Input = new [] {"American Football"} } }, 
    }; 

    client.IndexMany(bands); 

    var sports = new List<Sport> 
    { 
     new Sport { Id = 1, Suggest = new CompletionField<object> { Input = new [] {"Bowling"} } }, 
     new Sport { Id = 2, Suggest = new CompletionField<object> { Input = new [] {"Football"} } }, 
     new Sport { Id = 3, Suggest = new CompletionField<object> { Input = new [] {"Baseball"} } }, 
     new Sport { Id = 4, Suggest = new CompletionField<object> { Input = new [] {"Table Tennis"} } }, 
     new Sport { Id = 5, Suggest = new CompletionField<object> { Input = new [] {"American Football"} } }, 
    }; 

    client.IndexMany(sports); 
    client.Refresh(defaultIndex); 

    var suggestResponse = client.Suggest<Band>(s => s 
     .Completion("suggestion", cs => cs 
      .Text("Bo") 
      .Field(f => f.Suggest) 
     ) 
    ); 
} 

我們回來從以下我們建議致電

{ 
    "_shards" : { 
    "total" : 5, 
    "successful" : 5, 
    "failed" : 0 
    }, 
    "suggestion" : [ { 
    "text" : "Bo", 
    "offset" : 0, 
    "length" : 2, 
    "options" : [ { 
     "text" : "Bowling", 
     "score" : 1.0 
    }, { 
     "text" : "Bowling for Soup", 
     "score" : 1.0 
    } ] 
    } ] 
} 

我們就獲得了Band的建議鍵入並在結果中輸入Sport。也許不是我們所期望或想要的,但這就是建議者的工作方式。請注意,在.Suggest<T>()調用中,類型T用於提供對查詢中可能使用的屬性的強類型訪問。在本例中,.Suggest字段的Band類型。

這裏推薦的解決方案是爲不同類型分別設置不同的索引;您仍然可以在需要時跨越多個索引進行查詢,並避免在同一索引中存在多個類型時可能出現的缺陷。

除此之外,您可以通過使用Context Suggester並利用category context來完成類型映射。理想情況下,您希望使用文檔中存在的字段來爲類別提供靈活性,但是您可以根據需要使用元數據字段。我建議爲您的域調查和研究方法。

隨着我們前面的例子,如果我們現在包括在映射類上下文(相同的代碼之前,但這個更新的映射

client.CreateIndex(defaultIndex, ci => ci 
    .Mappings(m => m 
     .Map<Band>(l => l 
      .AutoMap() 
      .Properties(p => p 
       .Completion(c => c 
        .Name(n => n.Suggest) 
        .Context(sc => sc 
         .Category("type", csc => csc 
          // recommend that you use another field on 
          // the document here instead of a metadata field 
          .Field("_type") 
         ) 
        ) 
       ) 
      ) 
     ) 
     .Map<Sport>(l => l 
      .AutoMap() 
      .Properties(p => p 
       .Completion(c => c 
        .Name(n => n.Suggest) 
        .Context(sc => sc 
         .Category("type", csc => csc 
          // recommend that you use another field on 
          // the document here instead of a metadata field 
          .Field("_type") 
         ) 
        ) 
       ) 
      ) 
     ) 
    ) 
); 

而且使用類別方面,而搜索

var suggestResponse = client.Suggest<Band>(s => s 
    .Completion("suggestion", cs => cs 
     .Text("Bo") 
     .Field(f => f.Suggest) 
     .Context(d => d.Add("type", "band")) 
    ) 
); 

然後我們得到想要的結果

{ 
    "_shards" : { 
    "total" : 5, 
    "successful" : 5, 
    "failed" : 0 
    }, 
    "suggestion" : [ { 
    "text" : "Bo", 
    "offset" : 0, 
    "length" : 2, 
    "options" : [ { 
     "text" : "Bowling for Soup", 
     "score" : 1.0 
    } ] 
    } ] 
}