2016-04-22 39 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 
    } ] 
    } ] 
}