我正在尝试使用弹性搜索和NEST为我的网站创建搜索功能。你可以在下面看到我的代码,如果我搜索完整的(几乎是comlete)单词,我会得到结果。 也就是说,如果我寻找" Buttermilk"或者" Buttermil"我的文档中包含了" Buttermilk"。
这个词然而,我试图完成的是如果我搜索" Butter",我应该得到一个结果,所有三个文件都有以" Butter"开头的单词。我以为这是通过使用FuzzyLikeThis来解决的?
任何人都可以看到我做错了什么并指出了我正确的方向吗?
我创建了一个控制台应用程序以及您可以在此处看到的完整代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nest;
using Newtonsoft.Json;
namespace ElasticSearchTest
{
class Program
{
static void Main(string[] args)
{
var indexSettings = new IndexSettings();
indexSettings.Analysis.Analyzers["text-en"] = new SnowballAnalyzer { Language = "English" };
ElasticClient.CreateIndex("elastictesting", indexSettings);
var testItem1 = new TestItem {
Id = 1,
Name = "Buttermilk"
};
ElasticClient.Index(testItem1, "elastictesting", "TestItem", testItem1.Id);
var testItem2 = new TestItem {
Id = 2,
Name = "Buttercream"
};
ElasticClient.Index(testItem2, "elastictesting", "TestItem", testItem2.Id);
var testItem3 = new TestItem {
Id = 3,
Name = "Butternut"
};
ElasticClient.Index(testItem3, "elastictesting", "TestItem", testItem3.Id);
Console.WriteLine("Write search phrase:");
var searchPhrase = Console.ReadLine();
var searchResults = Search(searchPhrase);
Console.WriteLine("Number of search results: " + searchResults.Count());
foreach (var item in searchResults) {
Console.WriteLine(item.Name);
}
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
private static List<TestItem> Search(string searchPhrase)
{
var query = BuildQuery(searchPhrase);
var result = ElasticClient
.Search(query)
.Documents
.Select(d => d)
.Distinct()
.ToList();
return result;
}
public static ElasticClient ElasticClient
{
get
{
var localhost = new Uri("http://localhost:9200");
var setting = new ConnectionSettings(localhost);
setting.SetDefaultIndex("elastictesting");
return new ElasticClient(setting);
}
}
private static SearchDescriptor<TestItem> BuildQuery(string searchPhrase)
{
var querifiedKeywords = string.Join(" AND ", searchPhrase.Split(' '));
var filters = new BaseFilter[1];
filters[0] = Filter<TestItem>.Bool(b => b.Should(m => m.Query(q =>
q.FuzzyLikeThis(flt =>
flt.OnFields(new[] {
"name"
}).LikeText(querifiedKeywords)
.PrefixLength(2)
.MaxQueryTerms(1)
.Boost(2))
)));
var searchDescriptor = new SearchDescriptor<TestItem>()
.Filter(f => f.Bool(b => b.Must(filters)))
.Index("elastictesting")
.Type("TestItem")
.Size(500);
var jsons = JsonConvert.SerializeObject(searchDescriptor, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
return searchDescriptor;
}
}
class TestItem {
public int Id { get; set; }
[ElasticProperty(Analyzer = "text-en", Index = FieldIndexOption.analyzed)]
public string Name { get; set; }
}
}
编辑2014-04-01 11:18
好吧,我最终使用了MultiMatch和QueryString,所以这就是我的代码现在的样子。希望它可以帮助任何人。另外,我在TestItem中添加了一个Description属性来说明multimatch。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nest;
using Newtonsoft.Json;
namespace ElasticSearchTest
{
class Program
{
static void Main(string[] args)
{
var indexSettings = new IndexSettings();
ElasticClient.CreateIndex("elastictesting", indexSettings);
var testItem1 = new TestItem {
Id = 1,
Name = "Buttermilk",
Description = "butter with milk"
};
ElasticClient.Index(testItem1, "elastictesting", "TestItem", testItem1.Id);
var testItem2 = new TestItem {
Id = 2,
Name = "Buttercream",
Description = "Butter with cream"
};
ElasticClient.Index(testItem2, "elastictesting", "TestItem", testItem2.Id);
var testItem3 = new TestItem {
Id = 3,
Name = "Butternut",
Description = "Butter with nut"
};
ElasticClient.Index(testItem3, "elastictesting", "TestItem", testItem3.Id);
Console.WriteLine("Write search phrase:");
var searchPhrase = Console.ReadLine();
var searchResults = Search(searchPhrase);
Console.WriteLine("Number of search results: " + searchResults.Count());
foreach (var item in searchResults) {
Console.WriteLine(item.Name);
Console.WriteLine(item.Description);
}
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
private static List<TestItem> Search(string searchPhrase)
{
var query = BuildQuery(searchPhrase);
var result = ElasticClient
.Search(query)
.Documents
.Select(d => d)
.Distinct()
.ToList();
return result;
}
public static ElasticClient ElasticClient
{
get
{
var localhost = new Uri("http://localhost:9200");
var setting = new ConnectionSettings(localhost);
setting.SetDefaultIndex("elastictesting");
return new ElasticClient(setting);
}
}
private static SearchDescriptor<TestItem> BuildQuery(string searchPhrase)
{
var searchDescriptor = new SearchDescriptor<TestItem>()
.Query(q => q
.MultiMatch(m =>
m.OnFields(new[] {
"name",
"description"
}).QueryString(searchPhrase).Type(TextQueryType.PHRASE_PREFIX)
)
)
.Index("elastictesting")
.Type("TestItem")
.Size(500);
var jsons = JsonConvert.SerializeObject(searchDescriptor, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
return searchDescriptor;
}
}
class TestItem {
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
}
答案 0 :(得分:1)
而不是使用FuzzyLikequery ..使用前缀查询更快更准确..! 了解更多信息refer
curl -XPOST "http://localhost:9200/try/indextype/_search" -d'
{
"query": {
"prefix": {
"field": {
"value": "Butter"
}
}
}
}'
在NEST中创建以上查询并再试一次..!
答案 1 :(得分:1)
这与FuzzyLikeThis
无关。
您可以使用@BlackPOP开箱即用的前缀查询。
您也可以选择使用EdgeNGrams
,这会将您的输入标记为索引时间。结果与prefixquery
相比,性能更快,抵消了增加的索引大小。
要记住的一件事是prefixquery
仅适用于未分析的字段,因此如果您想在索引时进行任何分析,那么最好使用EdgeNGrams。
如果你不知道它们是什么,请阅读anaylzers等。 一些参考:
有关类似问题,请参阅How can I do a prefix search in ElasticSearch in addition to a generic query string?。