Elasticsearch Nest 通配符查询(带空格)

kha*_*kha 5 c# elasticsearch nest

简洁版本:

我想使用 Nest 编写一个弹性搜索查询来获取完整的索引项(ContentIndexables已索引的完整索引项(在我的例子中为我的自定义类型)。该查询受 [some string] + * 术语查询的约束(即 String.StartsWith(),其中 [some string] 可能包含也可能不包含空格。

这与CompletionSuggester我需要检索完整对象而不是字符串建议不同。

到目前为止我尝试过的:

当我查询不带空格的文本时,使用下面的代码返回所需的输出。但是,如果我的搜索词包含空格,则它不会返回预期结果。

以下是我搜索字段的方法:

var searchResults = _client.Search<ContentIndexable>(
            body =>
            body
                .Index(indexName)
                .Query(
                    query =>
                    query.QueryString(
                        qs => qs.
                                  OnFields(f => f.Title, f => f.TextContent)
                                  .Query(searchTerm + "*"))));
Run Code Online (Sandbox Code Playgroud)

这是一个演示如何重现问题的单元测试:

indexService.IndexUserItemsSync(testGuid, IndexType.submission, new ContentIndexable
        {
            ContentId = Guid.NewGuid(),
            TextContent = "Some description",
            Title = "title"
        });

        indexService.IndexUserItemsSync(testGuid, IndexType.submission, new ContentIndexable
        {
            ContentId = Guid.NewGuid(),
            TextContent = "Some description",
            Title = "title that is long"
        });

        indexService.IndexUserItemsSync(testGuid, IndexType.submission, new ContentIndexable
        {
            ContentId = Guid.NewGuid(),
            TextContent = "Some description",
            Title = "title that likes"
        });

        indexService.IndexUserItemsSync(testGuid, IndexType.submission, new ContentIndexable
        {
            ContentId = Guid.NewGuid(),
            TextContent = "Some description",
            Title = "titlethat"
        });

        var searchResult = indexService.SearchUserItems(testGuid, IndexType.submission, 10, "title");
        Assert.IsNotNull(searchResult);
// this one works
        Assert.AreEqual(4, searchResult.Count());

        var searchResult2 = indexService.SearchUserItems(testGuid, IndexType.submission, 10, "title that");
        Assert.IsNotNull(searchResult2);
// this one does not!!! searchREsult2.Count() evaluates to 0
        Assert.AreEqual(2, searchResult2.Count());
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,然后我输入“title that”,搜索结果为空,而不是我期望返回的两行。

更新: 更多信息:我在我的类型 ContentIndexable 上创建索引:

public class ContentIndexable : IIndexable
{
    public Guid ContentId { get; set; }
    public string Title { get; set; }
    public string TextContent { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

有了这个代码:

_client.CreateIndex(
    indexName,
    descriptor =>
    descriptor.AddMapping<ContentIndexable>(
        m => m.Properties(
            p => p.Completion(s => s
                                       .Name(n => n.Title)
                                       .IndexAnalyzer("standard")
                                       .SearchAnalyzer("standard")
                                       .MaxInputLength(30)
                                       .Payloads()
                                       .PreserveSeparators()
                                       .PreservePositionIncrements())
                     .Completion(s => s.Name(n => n.TextContent)
                                          .IndexAnalyzer("standard")
                                          .SearchAnalyzer("standard")
                                          .MaxInputLength(50)
                                          .Payloads()
                                          .PreserveSeparators()
                                          .PreservePositionIncrements())
                 )));
Run Code Online (Sandbox Code Playgroud)

我什至尝试在索引或查询时转义空格,string.Replace(" ", @"\ ")但这没有帮助。

将搜索类型更改为通配符也没有帮助:

var searchResults = _client.Search<ContentIndexable>(
            body =>
            body
                .Index(indexName)
                .Query(
                    query => query.Wildcard(qd => qd.OnField(f => f.Title).Value(searchTerm + "*"))));
Run Code Online (Sandbox Code Playgroud)

有谁知道我做错了什么?

请注意,我的CompletionSuggester版本适用于空格,但不幸的是仅返回字符串。我需要取出完整的项目才能获取ContentId. 我的 CompletionSuggester 实施:

public IEnumerable<string> GetAutoCompleteSuggestions(Guid userId, IndexType indexType, int size, string searchTerm)
    {
        string indexName = getIndexName(indexType, userId);

        var result = _client.Search<ContentIndexable>(
            body => body.Index(indexName)
                        .SuggestCompletion("content-suggest" + Guid.NewGuid(),
                                           descriptor => descriptor
                                                             .OnField(t => t.Title)
                                                             .Text(searchTerm)
                                                             .Size(size)));

        if (result.Suggest == null)
        {
            return new List<string>();
        }

        return (from suggest in result.Suggest
                from value in suggest.Value
                from options in value.Options
                select options.Text).Take(size);
    }
Run Code Online (Sandbox Code Playgroud)

我知道我可以接受这些建议,获取完整的值(这将产生我期望的两个项目),然后使用我的第一种方法进行完整的术语匹配,但这需要对 ElasticSearch 进行 2 次单独的调用(一个用于完整的建议者)第二个用于术语查询)但理想情况下,如果可能的话,我希望在没有往返的情况下完成此操作。

提前谢谢了,

Rob*_*Rob 4

这是如何处理现场问题的示例Title

将您的映射更改为类似的内容(或使用MultiField,但我找不到将字段映射为字符串并同时完成的选项):

client.CreateIndex(indexName, i => i
    .AddMapping<ContentIndexable>(m => m
        .Properties(
            ps => ps
                .Completion(c => c.Name("title.completion")
                    .IndexAnalyzer("standard")
                    .SearchAnalyzer("standard")
                    .MaxInputLength(30)
                    .Payloads()
                    .PreserveSeparators()
                    .PreservePositionIncrements())
                .String(s => s.Name(x => x.Title).CopyTo("title.completion")))));
Run Code Online (Sandbox Code Playgroud)

将您的更改SuggestCompletion

var result = client.Search<ContentIndexable>(body => body
    .Index(indexName)
    .SuggestCompletion("content-suggest" + Guid.NewGuid(),
        descriptor => descriptor
            .OnField(t => t.Title.Suffix("completion"))
            .Text("title")
            .Size(10)));
Run Code Online (Sandbox Code Playgroud)

QueryString

var searchResponse = client.Search<ContentIndexable>(body => body
    .Index(indexName)
    .Query(query => query
        .QueryString(
            qs => qs
                .OnFields(f => f.Title.Suffix("completion"))
                .Query("title tha" + "*")
                .MinimumShouldMatchPercentage(100))));
Run Code Online (Sandbox Code Playgroud)

该解决方案的问题在于我们为Title字段存储了两次数据。这就是为什么我之前提到使用MultiField会很棒,但我无法使用NEST.

希望这可以帮助。