带有空格的Elasticsearch Nest通配符查询

发布于 2021-02-01 11:50:25

精简版:

我想使用Nest编写一个elasticsearch查询,以获取ContentIndexables已被索引的完整索引项(在我的情况下为自定义类型)。该查询受[somestring] + *(即String.StartsWith())的术语查询的约束,其中[somestring]可能包含空格,也可能不包含空格。

这与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 + "*"))));

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

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());

如您所见,然后输入“ title that”,搜索返回为空,而不是我希望返回的两行。

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

public class ContentIndexable : IIndexable
{
    public Guid ContentId { get; set; }
    public string Title { get; set; }
    public string TextContent { get; set; }
}

使用此代码:

_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())
                 )));

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

将搜索类型更改为通配符也无济于事:

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

有人知道我在做什么错吗?

请注意,我的CompletionSuggester版本可以使用空格,但不幸的是只能返回字符串。我需要拿出 完整的物品
才能拿到ContentId。MY 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);
    }

我知道我可以接受建议,获得全部价值(这将导致我期望的两个项目),然后使用我的第一种方法进行全期匹配,但这需要对ElasticSearch进行2次单独的调用(一个用于完整的建议者和第二个用于术语查询),但理想情况下,如果可能的话,我希望不进行往返。

提前谢谢了,

关注者
0
被浏览
87
1 个回答
  • 面试哥
    面试哥 2021-02-01
    为面试而生,有面试问题,就找面试哥。

    这是您如何解决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")))));
    

    更改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)));
    

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

    该解决方案的问题是事实,我们为Title字段存储了两次数据。这就是为什么我前面提到使用MultiField很好,但是我无法使用NEST

    希望这可以帮助。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看