带过滤器的Elasticsearch建议

时间:2016-07-27 20:06:26

标签: elasticsearch nest

我要求提供正常工作的建议,但我还需要通过文档中的其他字段过滤建议。

这有可能实现吗?只要我知道,Elasticsearch就无法做到这一点。还有其他想法吗?

public async Task<ISuggestResponse> Suggest(string index, string projectId, string field, string text)
        {
            var suggestResponse = await _client.SuggestAsync<TDocument>(s => s
                                                                            .Index(index)
                                                                            .Completion("suggest", c => c
                                                                                    .Text(text)
                                                                                    .Context(con => con.Add("projectId", projectId))
                                                                                    .Field(field)
                                                                                    .Size(20)
                                                                                )
                                                                    );

        return suggestResponse;
    }

-----------更新--------------------

ElasticsearchConfig.cs

client.Map<Component>(d => d
        .Properties(props => props
            .String(s => s
                .Name("name"))
            .Completion(c => c
                .Name("componentSuggestion")
                .Analyzer("simple")
                .SearchAnalyzer("simple")
                .Context(context => context
                    .Category("projectId", cat => cat
                    .Field(field => field.ProjectId)))
                .Payloads()))
        .Properties(props => props.String(s => s.Name("id").NotAnalyzed()))
        .Properties(props => props.String(s => s.Name("projectId").NotAnalyzed())));

enter image description here

2 个答案:

答案 0 :(得分:3)

The Context Suggester 扩展了完成建议器,以便在类别或地理位置上提供基本过滤元素。这可能足以满足您的目的。

您可能想要采用的另一种方法是使用Context Suggester提供按类型搜索的建议,在完成类型映射的有效负载内索引每个文档的id;然后使用有效负载中返回的ID来搜索文档,此时应用您的附加过滤并仅返回与过滤匹配的文档ID。最后,使用这些文档ID来获取原始建议响应中的建议。

修改

以下是使用Context Suggester

的完整示例
void Main()
{
    var componentsIndex = "components";
    var connectionPool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
    var settings = new ConnectionSettings(connectionPool)
        // use component index when working with
        // Component Poco type
        .InferMappingFor<Component>(m => m
            .IndexName(componentsIndex)
        );

    var client = new ElasticClient(settings);

    // make this example repeatable, so delete index if
    // it already exists
    if (client.IndexExists(componentsIndex).Exists)
        client.DeleteIndex(componentsIndex);

    // for example purposes, only use one shard and no replicas
    // NOT RECOMMENDED FOR PRODUCTION
    client.CreateIndex(componentsIndex, c => c
        .Settings(s => s
            .NumberOfShards(1)
            .NumberOfReplicas(0)
        )
    );

    client.Map<Component>(d => d
        .Index(componentsIndex)
        // infer mapping of fields from property of the POCO.
        // This means we don't need to explicitly specify all 
        // mappings in .Properties()
        .AutoMap()
        // Now, override any inferred mappings from automapping
        .Properties(props => props
            .Completion(c => c
                .Name(n => n.ComponentSuggestion)
                .Context(context => context
                    .Category("projectId", cat => cat
                        .Field(field => field.ProjectId)
                    )
                )
                .Payloads()
            )
            .String(s => s
                .Name(n => n.Id)
                .NotAnalyzed()
            )
            .String(s => s
                .Name(n => n.ProjectId)
                .NotAnalyzed()
            )
        )
    );

    var components = new[] {
        new Component
        {
            Id = "1",
            Name = "Component Name 1",
            ComponentSuggestion = new CompletionField<object>
            {
                Input = new [] { "Component Name 1" },
                Output = "Component Name 1"
            },
            ProjectId = "project_id"
        },
        new Component
        {
            Id = "2",
            Name = "Component Name 2",
            ComponentSuggestion = new CompletionField<object>
            {
                Input = new [] { "Component Name 2" },
                Output = "Component Name 2"
            },
            ProjectId = "project_id_2"
        }
    };

    // index some components with different project ids
    client.IndexMany(components);

    // refresh the index to make the newly indexed documents available for
    // search. Useful for demo purposes but,
    // TRY TO AVOID CALLING REFRESH IN PRODUCTION     
    client.Refresh(componentsIndex);

    var projectId = "project_id";

    var suggestResponse = client.Suggest<Component>(s => s
        .Index(componentsIndex)
        .Completion("suggester", c => c
            .Field(f => f.ComponentSuggestion)
            .Text("Compon")
            .Context(con => con.Add("projectId", projectId))
            .Size(20)
        )
    );

    foreach (var suggestion in suggestResponse.Suggestions["suggester"].SelectMany(s => s.Options))
    {
        Console.WriteLine(suggestion.Text);
    }
}

public class Component
{
    public string Id { get; set; }

    public string Name { get; set; }

    public string ProjectId { get; set; }

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

根据Component Name 1 projectId

的上下文,这只会产生一个建议"project_id"

答案 1 :(得分:2)

您应该使用context suggester而不是完成建议器,其目标是允许您为完成建议者指定其他类别或地理位置上下文。

如果我没弄错的话,NEST通过Context属性提供上下文建议器作为完成建议器的一部分。

public async Task<ISuggestResponse> Suggest(string index, string field, string text)
    {
        var suggestResponse = await _client.SuggestAsync<TDocument>(s => s
              .Index(index)
              .Completion("suggest", c => c
                    .Text(text)
                    .Context(con => con.Add("your_field", "text"))
                    .Field(field)
                    .Size(20)
              )
        );

        return suggestResponse;
    }

您还需要更改映射中的完成字段,以声明上下文。