我有一个搜索字符串,
Tulip INN Riyadhh
Tulip INN Riyadhh LUXURY
Suites of Tulip INN RIYAHdhh
如果我提及
,我需要搜索字词 *Tulip INN Riyadhh*
它必须返回上面的所有三个,我有限制,我必须实现这个没有QueryParser或Analyzer,它必须只有BooleanQuery / WildCardQuery /等....
此致 拉加
答案 0 :(得分:3)
这里需要的是PhraseQuery
。让我解释一下。
我不知道你正在使用哪种分析仪,但我认为你有一个非常简单的分析器,它只是将文本转换为小写。不要告诉我你没有使用anlayzer,因为Lucene必须完成任何工作,至少在索引阶段 - 这就是定义标记器和令牌过滤器链的原因。 / p>
以下是此示例中字符串的标记方式:
tulip
inn
ryiadhh
tulip
inn
ryiadhh
luxury
suites
of
tulip
inn
ryiadhh
请注意这些都包含令牌序列tulip
inn
ryiadhh
。一系列令牌就是PhraseQuery
正在寻找的东西。
在Lucene.Net构建中,这样的查询看起来像这样(未经测试):
var query = new PhraseQuery();
query.Add(new Term("propertyName", "tulip"));
query.Add(new Term("propertyName", "inn"));
query.Add(new Term("propertyName", "ryiadhh"));
请注意,这些术语需要与分析器生成的术语相匹配(在此示例中,它们全部为小写)。 QueryParser
通过分析器运行部分查询,为您完成这项工作,但如果您不使用解析器,则必须自己完成。
现在,为什么不会WildcardQuery
或RegexQuery
在这种情况下工作?这些查询始终与单个术语匹配,但您需要匹配有序的术语序列。例如,WildcardQuery
一词Riyadhh*
会找到所有以Riyadhh
开头的词。
包含BooleanQuery
TermQuery
条款集合的MUST
将匹配任何恰好包含这3个字词的文本 - 不完全符合您的要求。
答案 1 :(得分:1)
Lucas有正确的想法,但有一个更专业的Create Table Temp1
(Load_Dt Date,
ID Number,
Name Varchar2(10));
可用于根据索引中已有的数据构建查询,以获得前缀匹配demonstrated in this unit test 。 MultiPhraseQuery
的文档内容为:
MultiPhraseQuery
是MultiPhraseQuery
的通用版本,添加了方法PhraseQuery
。要使用此类,要搜索短语" Microsoft app *"首先在术语" Microsoft"上使用Add(Term[])
,然后找到所有包含" app"使用Add(Term)
作为前缀,并使用IndexReader.GetTerms(Term)
将其添加到查询中。
正如Lucas指出的那样,MultiPhraseQuery.Add(Term[] terms)
*something
是进行后缀匹配的方法,前提是您了解其性能影响。
然后可以将它们与WildCardQuery
组合以获得您想要的结果。
BooleanQuery
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Lucene.Net.Util;
using System;
using System.Collections.Generic;
namespace LuceneSQLLikeSearch
{
class Program
{
static void Main(string[] args)
{
// Prepare...
var dir = new RAMDirectory();
var writer = new IndexWriter(dir,
new IndexWriterConfig(LuceneVersion.LUCENE_48,
new StandardAnalyzer(LuceneVersion.LUCENE_48)));
WriteIndex(writer);
// Search...
var reader = writer.GetReader(false);
// Get all terms that end with tulip
var wildCardQuery = new WildcardQuery(new Term("field", "*tulip"));
var multiPhraseQuery = new MultiPhraseQuery();
multiPhraseQuery.Add(new Term("field", "inn"));
// Get all terms that start with riyadhh
multiPhraseQuery.Add(GetPrefixTerms(reader, "field", "riyadhh"));
var query = new BooleanQuery();
query.Add(wildCardQuery, Occur.SHOULD);
query.Add(multiPhraseQuery, Occur.SHOULD);
var result = ExecuteSearch(writer, query);
foreach (var item in result)
{
Console.WriteLine("Match: {0} - Score: {1:0.0########}",
item.Value, item.Score);
}
Console.ReadKey();
}
}
}
在这里,我们扫描索引以查找以传入前缀开头的所有术语。然后将这些条款添加到public static void WriteIndex(IndexWriter writer)
{
Document document;
document = new Document();
document.Add(new TextField("field", "Tulip INN Riyadhh", Field.Store.YES));
writer.AddDocument(document);
document = new Document();
document.Add(new TextField("field", "Tulip INN Riyadhh LUXURY", Field.Store.YES));
writer.AddDocument(document);
document = new Document();
document.Add(new TextField("field", "Suites of Tulip INN RIYAHdhh", Field.Store.YES));
writer.AddDocument(document);
document = new Document();
document.Add(new TextField("field", "Suites of Tulip INN RIYAHdhhll", Field.Store.YES));
writer.AddDocument(document);
document = new Document();
document.Add(new TextField("field", "myTulip INN Riyadhh LUXURY", Field.Store.YES));
writer.AddDocument(document);
document = new Document();
document.Add(new TextField("field", "some bogus data that should not match", Field.Store.YES));
writer.AddDocument(document);
writer.Commit();
}
。
MultiPhraseQuery
public static Term[] GetPrefixTerms(IndexReader reader, string field, string prefix)
{
var result = new List<Term>();
TermsEnum te = MultiFields.GetFields(reader).GetTerms(field).GetIterator(null);
te.SeekCeil(new BytesRef(prefix));
do
{
string s = te.Term.Utf8ToString();
if (s.StartsWith(prefix, StringComparison.Ordinal))
{
result.Add(new Term(field, s));
}
else
{
break;
}
} while (te.Next() != null);
return result.ToArray();
}
public static IList<SearchResult> ExecuteSearch(IndexWriter writer, Query query)
{
var result = new List<SearchResult>();
var searcherManager = new SearcherManager(writer, true, null);
// Execute the search with a fresh indexSearcher
searcherManager.MaybeRefreshBlocking();
var searcher = searcherManager.Acquire();
try
{
var topDocs = searcher.Search(query, 10);
foreach (var scoreDoc in topDocs.ScoreDocs)
{
var doc = searcher.Doc(scoreDoc.Doc);
result.Add(new SearchResult
{
Value = doc.GetField("field")?.GetStringValue(),
// Results are automatically sorted by relevance
Score = scoreDoc.Score,
});
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
searcherManager.Release(searcher);
searcher = null; // Don't use searcher after this point!
}
return result;
}
如果这看起来很麻烦,请注意public class SearchResult
{
public string Value { get; set; }
public float Score { get; set; }
}
可以模仿&#34; SQL LIKE&#34;查询。正如here所指出的那样,QueryParser
上的AllowLeadingWildCard
可以选择轻松构建正确的查询序列。目前还不清楚为什么你有一个你不能使用它的约束,因为它绝对是完成工作的最简单方法。