Elasticsearch建议是两种类型的合并结果

时间:2016-04-22 20:28:24

标签: elasticsearch nest

我在一个索引中有2个类型,并且都有Suggest字段(根据需要)

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
                };

        }
    }
}

AND

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;
    }

创建文档类型如下

 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的结果。请建议

由于

1 个答案:

答案 0 :(得分:0)

建议者在索引级别工作,即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
    } ]
  } ]
}