Elasticsearch Nest 带空格的通配符查询
Elasticsearch Nest wildcard query with spaces
短版:
我想使用 Nest 编写一个弹性搜索查询来获取已编入索引的完整索引项(ContentIndexables
在我的例子中是我的自定义类型)。该查询受 [some string] + * 的术语查询(即 String.StartsWith() 其中 [some string] 可能包含也可能不包含空格。
这与 CompletionSuggester
不同,因为我需要检索完整的对象而不是字符串建议。
目前我尝试过的:
当我查询不带空格的文本时,所需的输出是 return 使用以下代码编辑的。但是,如果我的搜索词包含空格,则不会 return 预期结果。
以下是我搜索字段的方式:
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",搜索结果为空,而不是我期望 return.
的两行
更新:
更多信息:
我在我的类型 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
版本适用于空格,但不幸的是只能使用 returns 字符串。我需要取出 完整的项目 才能获取 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);
}
我知道我可以采纳这些建议,得到完整的值(这将产生我期待的两个项目),然后使用我的第一种方法进行完整的术语匹配,但这需要对 ElasticSearch 进行 2 次单独调用(一个用于完整的建议者,第二个用于术语查询)但理想情况下,如果可能的话,我想在没有往返的情况下进行。
非常感谢,
这是您如何处理 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
.
希望对您有所帮助。
短版:
我想使用 Nest 编写一个弹性搜索查询来获取已编入索引的完整索引项(ContentIndexables
在我的例子中是我的自定义类型)。该查询受 [some string] + * 的术语查询(即 String.StartsWith() 其中 [some string] 可能包含也可能不包含空格。
这与 CompletionSuggester
不同,因为我需要检索完整的对象而不是字符串建议。
目前我尝试过的:
当我查询不带空格的文本时,所需的输出是 return 使用以下代码编辑的。但是,如果我的搜索词包含空格,则不会 return 预期结果。
以下是我搜索字段的方式:
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",搜索结果为空,而不是我期望 return.
的两行更新: 更多信息: 我在我的类型 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
版本适用于空格,但不幸的是只能使用 returns 字符串。我需要取出 完整的项目 才能获取 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);
}
我知道我可以采纳这些建议,得到完整的值(这将产生我期待的两个项目),然后使用我的第一种方法进行完整的术语匹配,但这需要对 ElasticSearch 进行 2 次单独调用(一个用于完整的建议者,第二个用于术语查询)但理想情况下,如果可能的话,我想在没有往返的情况下进行。
非常感谢,
这是您如何处理 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
.
希望对您有所帮助。