精简版:
我想使用Nest编写一个elasticsearch查询,以获取ContentIndexables已被索引的完整索引项(在我的情况下为自定义类型)。该查询受[somestring] + *(即String.StartsWith())的术语查询的约束,其中[somestring]可能包含空格,也可能不包含空格。
ContentIndexables
这与CompletionSuggester由于我需要检索完整对象而不是字符串建议而不同。
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(" ", @"\ ")但这没有帮助。
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实施:
ContentId
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现场问题的示例。
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为
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以
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
希望这可以帮助。