高级Lucene查询示例

本文是我们名为“ Apache Lucene基础知识 ”的学院课程的一部分。

在本课程中,您将了解Lucene。 您将了解为什么这样的库很重要,然后了解Lucene中搜索的工作方式。 此外,您将学习如何将Lucene Search集成到您自己的应用程序中,以提供强大的搜索功能。 在这里查看 !

目录

1.引言 2.Lucene查询 3,Lucene查询API 4,基本搜索
4.1。条款 4.2。通配符查询 4.3。布尔运算符 4.3分组 4.4。短语查询 4.5。范围查询 4.6。前缀查询 4.7。模糊查询

1.引言

在上一章中,我们了解了Lucene搜索引擎的不同组件 。 我们还使用lucene索引和搜索程序构建了一个小型搜索应用程序。 在本章中,我们将讨论Lucene查询。

2.Lucene查询

Lucene具有用于查询其索引的自定义查询语法。 查询分为术语和运算符。 术语有两种类型: 1 . 单词2.短语 。 单个术语是一个单词,例如“测试”或“样本”。 词组是一组用双引号括起来的单词,例如“ welcome lucene”。 可以将多个术语与布尔运算符组合在一起以形成更复杂的查询。 对于Lucene Java,TermQuery是最原始的查询。 然后是BooleanQuery,PhraseQuery和许多其他Query子类可供选择。

字段执行搜索时,我们可以指定要搜索的字段。任何现有的字段名称都可以用作字段名称。 语法为FieldName:VALUE 。 有一些特殊的字段类型具有自己的语法来定义查询词。 例如,DateTime:ModificationDate:>'2010-09-01 12:00:00'我们将在后面的部分中解释对这些字段的搜索操作。

3,Lucene查询API

当Lucene的QueryParser解析人类可读的查询时,它将转换为Query类的单个具体子类。 我们需要对基础的具体Query子类有所了解。 下表列出了相关的子类,它们的用途以及一些示例表达式:

查询实施 目的 样本表达
TermQuery 单项查询,实际上是一个单词。 雷诺
PhraseQuery 多个项按顺序排列或彼此接近的匹配项 “前方点亮”
RangeQuery 用开始和结束词之间的词匹配文档,包括或不包括端点。 [A到Z]

{A到Z}

WildcardQuery 轻量级的,类似于正则表达式的术语匹配语法。 j * v?

f ?? bar

PrefixQuery 匹配以指定字符串开头的所有术语。 起司*
FuzzyQuery Levenshtein紧密匹配算法。 树〜
BooleanQuery 将其他查询实例聚合为允许AND,OR和NOT逻辑的复杂表达式。 雷诺和“前方点亮”

奶酪*-奶酪


所有这些Query实现都在org.apache.lucene.search包中。 BooleanQuery是一种特殊情况,因为它是一个聚合其他查询(包括用于复杂表达式的嵌套BooleanQuery )的Query容器。

这是一个基于查询片段的BooleanQuery 。 在这里,我们可以看到QueryParser创建的查询与API创建的查询等效:

public class RulezTest extends TestCase { public void testJavaNotDotNet() throws Exception { BooleanQuery apiQuery = new BooleanQuery(); apiQuery.add(new TermQuery(new Term("contents", "java")), true, false); apiQuery.add(new TermQuery(new Term("contents", "net")), true, false); apiQuery.add(new TermQuery(new Term("contents", "dot")), false, true); Query qpQuery = QueryParser.parse("java AND net NOT dot", "contents", new StandardAnalyzer()); // Query and subclasses behave as expected with .equals assertEquals(qpQuery, apiQuery); } 
}

Query类的一些有趣的功能是它们的toString方法。 每个Query子类都会生成等效的QueryParserexpression (尽管不一定在文本上精确)。 有两种变体:一种是标准的Object.toString重写方法,另一种接受默认字段名称。 下面的测试案例演示了这两种方法的工作原理,并说明了如何返回等效(但不是确切)的表达式。

public void testToString() throws Exception { Query query = QueryParser.parse("java AND net NOT dot", "contents", new StandardAnalyzer()); assertEquals("+java +net -dot", query.toString("contents")); assertEquals("+contents:java +contents:net -contents:dot", query.toString()); 
}

注意,解析的表达式是“ java AND net NOT dot”,但是从toString方法返回的表达式使用了缩写语法“ + java + net -dot”。 我们的第一个测试用例( testJavaNotDotNet )证明了底层查询对象本身是等效的。

no-arg toString方法不对每个术语的字段名称做任何假设,并使用字段选择器语法明确指定它们。 使用这些toString方法可方便地诊断QueryParser问题。

4,基本搜索

在大多数情况下,您要查找单个术语或短语,即由双引号引起的一组单词(“示例应用程序”)。 在这些情况下,我们将在其默认索引数据中查找包含这些单词的内容,这些内容包含内容的所有相关文本。

在更复杂的情况下,我们可能需要根据要查找的内容的类型或位置进行某些过滤,或者我们要在特定字段中进行搜索。 在这里,我们可以学习如何构建更复杂的查询,这些查询可用于有效地在大型存储库中查找内容。

4.1。条款

假设我们要在标签字段中使用关键字“博客”进行搜索。 语法将是

tag :  blog

现在,我们将在标签字段中使用短语“ lucene blog”进行搜索。 为此,语法将是

tag :   "lucene blog"

现在,让我们在标签字段中搜索“ lucene blog”,然后在正文中搜索“ technical blog”,

tag : "lucene blog" AND body : "technical blog"

假设我们要在标签字段中搜索短语“ lucene blog”,在正文中搜索“技术博客”,或者在标签字段中搜索“ searching blog”,

(tag : "lucene blog" AND body : "technical blog") OR tag : "searching blog"

如果我们要在标记字段中搜索“博客”而不是“ lucene”,则语法看起来会相似,

tag : blog -tag : lucene

4.2。通配符查询

Lucene支持在单个术语内(而不是在短语查询中)单字符和多字符通配符搜索。

  1. 要执行单个字符通配符搜索,请使用“?” 符号。
  2. 要执行多字符通配符搜索,请使用“ *”符号。

单字符通配符搜索查找与替换了单个字符的词匹配的术语。 例如,要搜索“文本”或“测试”,我们可以使用搜索:te?t

多字符通配符搜索将查找0个或多个字符。 例如,要搜索测试,测试或测试员,我们可以使用搜索:

test*

我们还可以在术语中间使用通配符搜索。

te*t

这是Lucene通配符搜索的示例,

假设我们在“文件”目录中有两个文件。

  1. test-foods.txt

    以下是Deron喜欢的一些食物:

    hamburger
    french fries
    steak mushrooms artichokes

  2. sample-food.txt

    以下是妮可喜欢的一些食物:

    apples
    bananas
    salad mushrooms cheese

现在,我们看一下LuceneWildcardQueryDemo类。 此类基于上述文本文件通过createIndex()方法创建索引,此后,它尝试对该索引执行8个通配符搜索。 使用WildcardQuery类执行其中四个搜索,而使用QueryParser类执行其他四个搜索。

首先使用createIndex()方法对以上两个文件建立索引。

public static void createIndex() throws CorruptIndexException, LockObtainFailedException, IOException {Analyzer analyzer = new StandardAnalyzer();boolean recreateIndexIfExists = true;IndexWriter indexWriter = new IndexWriter(INDEX_DIRECTORY, analyzer, recreateIndexIfExists);File dir = new File(FILES_TO_INDEX_DIRECTORY);File[] files = dir.listFiles();for (File file : files) {Document document = new Document();String path = file.getCanonicalPath();document.add(new Field(FIELD_PATH, path, Field.Store.YES, Field.Index.UN_TOKENIZED));Reader reader = new FileReader(file);document.add(new Field(FIELD_CONTENTS, reader));indexWriter.addDocument(document);}indexWriter.optimize();indexWriter.close();
}

为了使用查询解析器执行搜索操作,我们可以添加一个名为searchIndexWithQueryParser()的方法,

public static void searchIndexWithQueryParser(String whichField, String searchString) throws IOException,ParseException {System.out.println("\\nSearching for '" + searchString + "' using QueryParser");Directory directory = FSDirectory.getDirectory(INDEX_DIRECTORY);IndexSearcher indexSearcher = new IndexSearcher(directory);QueryParser queryParser = new QueryParser(whichField, new StandardAnalyzer());Query query = queryParser.parse(searchString);System.out.println("Type of query: " + query.getClass().getSimpleName());Hits hits = indexSearcher.search(query);displayHits(hits);
}

使用以下代码在searchIndexWithWildcardQuery()方法中执行WildcardQuery查询:

Directory directory = FSDirectory.getDirectory(INDEX_DIRECTORY); IndexSearcher indexSearcher = new IndexSearcher(directory); Term term = new Term(whichField, searchString); Query query = new WildcardQuery(term); Hits hits = indexSearcher.search(query);

QueryParser查询通过以下方式在searchIndexWithQueryParser()方法中执行:

Directory directory = FSDirectory.getDirectory(INDEX_DIRECTORY); IndexSearcher indexSearcher = new IndexSearcher(directory); QueryParser queryParser = new QueryParser(whichField, new StandardAnalyzer()); Query query = queryParser.parse(searchString); Hits hits = indexSearcher.search(query);

从我们的main()方法可以看到, LuceneWildcardQueryDemo类执行八个通配符搜索:

searchIndexWithWildcardQuery(FIELD_CONTENTS, "t*t"); searchIndexWithQueryParser(FIELD_CONTENTS, "t*t"); searchIndexWithWildcardQuery(FIELD_CONTENTS, "sam*"); searchIndexWithQueryParser(FIELD_CONTENTS, "sam*"); searchIndexWithWildcardQuery(FIELD_CONTENTS, "te?t"); searchIndexWithQueryParser(FIELD_CONTENTS, "te?t"); searchIndexWithWildcardQuery(FIELD_CONTENTS, "*est"); try { searchIndexWithQueryParser(FIELD_CONTENTS, "*est"); } catch (ParseException pe) { pe.printStackTrace(); }

最后,我们将使用类似的方法打印每次搜索操作的命中数,

public static void displayHits(Hits hits) throws CorruptIndexException, IOException {System.out.println("Number of hits: " + hits.length());Iterator<Hit> it = hits.iterator();while (it.hasNext()) {Hit hit = it.next();Document document = hit.getDocument();String path = document.get(FIELD_PATH);System.out.println("Hit: " + path);}
}

如果我们运行上面的代码,它将向我们显示,

Searching for 't*t' using WildcardQuery
Number of hits: 1
Hit: /home/debarshi/workspace/Test/filesToIndex/test-foods.txt
Searching for 't*t' using QueryParser
Type of query: WildcardQuery
Number of hits: 1
Hit: /home/debarshi/workspace/Test/filesToIndex/test-foods.txt
Searching for 'sam*' using WildcardQuery
Number of hits: 1
Hit: /home/debarshi/workspace/Test/filesToIndex/sample-foods.txt
Searching for 'sam*' using QueryParser
Type of query: PrefixQuery
Number of hits: 1
Hit: /home/debarshi/workspace/Test/filesToIndex/sample-foods.txt
Searching for 'te?t' using WildcardQuery
Number of hits: 1
Hit: /home/debarshi/workspace/Test/filesToIndex/test-foods.txt
Searching for 'te?t' using QueryParser
Type of query: WildcardQuery
Number of hits: 1
Hit: /home/debarshi/workspace/Test/filesToIndex/test-foods.txt
Searching for '*est' using WildcardQuery
Number of hits: 1
Hit: /home/debarshi/workspace/Test/filesToIndex/test-foods.txt
Searching for '*est' using QueryParserorg.apache.lucene.queryParser.ParseException: Cannot parse '*est': '*' or '?' not allowed as first character in WildcardQuery at org.apache.lucene.queryParser.QueryParser.parse(QueryParser.java:175) at LuceneWildcardQueryDemo.searchIndexWithQueryParser(LuceneWildcardQueryDemo.java:81) at LuceneWildcardQueryDemo.main(LuceneWildcardQueryDemo.java:46)
  1. 第一个查询使用带有“ t * t”的WildcardQuery对象。 由于“ t * t”与索引中的“ test”匹配,因此此查询返回1次匹配。
  2. 第二个查询使用QueryParser查询“ t * t”。 QueryParser parse()方法返回WildcardQuery ,并且该查询返回1个匹配项,因为它与第一个查询基本相同。
  3. 第三个查询使用带有“ sam *”的WildcardQuery对象。 由于“ sam *”与“ sample”匹配,因此该通配符查询获得了成功。
  4. 第四个查询使用带有“ sam *”的QueryParser 。 但是请注意,QueryParser的parse()方法返回PrefixQuery而不是WildcardQuery 。 由于星号在“ sam *”的末尾。 由于“ sam *”与“ sample”匹配,因此该针对“ sam *”的PrefixQuery命中。
  5. 第五个查询是WildcardQuery ,它在其搜索词“ te?t”中使用问号。 问号可以匹配一个字符。 由于“ te?t”与“ test”匹配,因此搜索返回1个匹配项。
  6. 第六个查询使用带有“ te?t”的QueryParser 。 QueryParser parse()方法返回WildcardQuery ,并且与第五个查询一样,该命中率WildcardQuery
  7. 第七个查询是“ * est”的WildcardQuery查询。 由于“ test”匹配“ * est”,因此它收到一个匹配。 通常,在第一个字符为通配符的情况下执行查询不是一个好主意。
  8. 第八个查询是“ * est”的QueryParser查询。 请注意, QueryParser对象甚至不允许我们执行第一个字符为星号的查询。 引发解析异常。

4.3。布尔运算符

布尔运算符允许通过逻辑运算符组合术语。 Lucene支持AND,“ +”,OR,NOT和“-”作为布尔运算符(注意:布尔运算符必须为ALL CAPS)。

OR运算符是默认的合取运算符。 这意味着如果两个术语之间没有布尔运算符,则使用OR运算符。 OR运算符链接两个术语,如果文档中存在两个术语中的任何一个,则查找匹配的文档。 这等效于使用集合的并集。 符号|| 可以代替单词OR。

要搜索包含“ jakarta apache”或仅包含“ jakarta”的文档,请使用查询:

"jakarta apache" jakarta

要么

"jakarta apache" OR jakarta

AND运算符匹配两个术语都存在于单个文档的文本中任意位置的文档。 这等效于使用集合的交点。 可以使用符号&&代替单词AND。

要搜索包含“ jakarta apache”和“ Apache Lucene”的文档,请使用查询:

"jakarta apache" AND "Apache Lucene"

+

“ +”或必需的运算符要求“ +”符号后的术语存在于单个文档的字段中。

要搜索必须包含“ jakarta”且可能包含“ lucene”的文档,请使用以下查询:

+jakarta lucene

NOT运算符排除包含NOT之后的术语的文档。 这等效于使用集的区别。 符号! 可以代替“非”一词使用。

要搜索包含“ jakarta apache”但不包含“ Apache Lucene”的文档,请使用以下查询:

"jakarta apache" NOT "Apache Lucene"

注意:NOT运算符不能仅使用一个术语。 例如,以下搜索将不返回任何结果:

NOT "jakarta apache"

“-”

“-”或禁止运算符排除包含在“-”符号后的术语的文档。

要搜索包含“ jakarta apache”但不包含“ Apache Lucene”的文档,请使用以下查询:

"jakarta apache" -"Apache Lucene"

4.3分组

Lucene支持使用括号将子句分组以形成子查询。 如果要控制查询的布尔逻辑,这可能非常有用。

要搜索“ jakarta”或“ apache”和“网站”,请使用查询:

(jakarta OR apache) AND website

这样可以消除任何混乱,并确保您必须存在该网站,并且可能存在“雅加达”或“ apache”一词。

现场分组

Lucene支持使用括号将多个子句分组到一个字段中。

要搜索包含单词“ return”和短语“ pink panther”的标题,请使用以下查询:

title:(+return +"pink panther")

转义特殊字符

Lucene支持转义查询语法中包含的特殊字符。 当前列表的特殊字符为:

+ – && || ! (){} [] ^”〜*吗? :\

要转义这些字符,请在字符前使用“ \”(反斜杠)。 例如,要搜索(1 + 1):2,请使用查询:

\\(1\\+1\\)\\:2

4.4。短语查询

Lucene中的PhraseQuery匹配包含特定术语序列的文档。 PhraseQuery使用存储在索引中的术语的位置信息。

查询短语中单词之间允许的其他单词的数量称为“斜率”。 可以通过调用setSlop方法进行设置。 如果为零,则为精确短语搜索。 对于较大的值,其工作方式类似于WITHIN或NEAR运算符。

斜率实际上是一个编辑距离,其中单位对应于查询短语中词条移动的位置。 例如,要切换两个单词的顺序需要两个步骤(第一个步骤将单词彼此放在首位),因此要允许对短语进行重新排序,斜率必须至少为两个。

较精确的匹配比不精确的匹配得分更高,因此搜索结果按精确性排序。 默认情况下,斜率为零,要求完全匹配。

PhraseQuery还支持多个术语短语。

短语查询可以与其他术语组合,也可以与BooleanQuery组合使用。 默认情况下,子句的最大数量限制为1,024。

在前面的Lucene通配符查询示例中,我们已经基于两个文本文件完成了搜索操作。 现在,我们将尝试在Lucene中使用PhraseQuery查找匹配的短语。

为此,我们将引入一个新方法searchIndexWithPhraseQuery()代替searchIndexWithWildcardQuery()方法,该方法采用两个字符串表示文档中的单词和一个倾斜值。 它通过基于“ contents”字段以及string1和string2参数添加两个Term对象来构造PhraseQuery 。 然后,它使用setSlop()方法设置PhraseQuery对象的setSlop()值。 通过将PhraseQuery对象传递给IndexSearcher的search()方法来进行search() 。 这是代码,

public static void searchIndexWithPhraseQuery(String string1, String string2, int slop) throws IOException,ParseException {Directory directory = 	FSDirectory.getDirectory(INDEX_DIRECTORY);IndexSearcher indexSearcher = new IndexSearcher(directory);Term term1 = new Term(FIELD_CONTENTS, string1);Term term2 = new Term(FIELD_CONTENTS, string2);PhraseQuery phraseQuery = new PhraseQuery();phraseQuery.add(term1);phraseQuery.add(term2);phraseQuery.setSlop(slop);displayQuery(phraseQuery);Hits hits = indexSearcher.search(phraseQuery);displayHits(hits);
}

而且,我们从main()调用此方法,

searchIndexWithPhraseQuery("french", "fries", 0);searchIndexWithPhraseQuery("hamburger", "steak", 0);searchIndexWithPhraseQuery("hamburger", "steak", 1);searchIndexWithPhraseQuery("hamburger", "steak", 2);searchIndexWithPhraseQuery("hamburger", "steak", 3);searchIndexWithQueryParser("french fries"); // BooleanQuerysearchIndexWithQueryParser("\\"french fries\\""); // PhaseQuerysearchIndexWithQueryParser("\\"hamburger steak\\"~1"); // PhaseQuerysearchIndexWithQueryParser("\\"hamburger steak\\"~2"); // PhaseQuery

第一个查询以斜率0搜索“ french”和“ fries”,这意味着短语搜索最终是对“ french fries”的搜索,其中“ french”和“ fries”彼此相邻。 由于这存在于test-foods.txt中,因此我们获得了1次点击。

在第二个查询中,我们搜索坡度为0的“汉堡”和“牛排”。由于在两个文档中都不存在“汉堡”和“牛排”,因此得到0个匹配。 第三个查询还涉及对“汉堡包”和“牛排”的搜索,但斜率为1。这些单词彼此之间的距离不超过1个单词,因此我们获得0次匹配。

第四个查询以“ 2”的斜率搜索“汉堡”和“牛排”。在test-foods.txt文件中,我们有“……汉堡薯条……”字样。 由于“汉堡”和“牛排”彼此之间不超过两个字,因此我们获得1分。 第五个短语查询是相同的搜索,但斜率为3。由于“汉堡包”和“牛排”彼此带有三个单词(彼此是两个单词),因此命中率为1。

接下来的四个查询使用QueryParser 。 注意,在第一个QueryParser查询中,我们得到一个BooleanQuery而不是PhraseQuery 。 这是因为我们传递了QueryParser的parse()方法“炸薯条”而不是“ \”炸薯条\””。 如果我们希望QueryParser生成PhraseQuery,则搜索字符串需要用双引号引起来。 下一个查询确实会搜索“ \”炸薯条\”,并且我们可以看到它生成了一个PhraseQuery (默认PhraseQuery为0),并响应该查询获得了1次PhraseQuery

最后两个QueryParser查询演示了设置倾斜值。 我们可以看到,可以在搜索字符串的双引号后面设置斜率值,并在其后加上斜线号(〜)和斜率号。

4.5。范围查询

与专有术语范围内的文档匹配的Query 。 它允许匹配字段值在RangeQuery指定的上下限之间的RangeQuery 。 范围查询可以包含上限或下限,也可以不包括上限和下限。 排序是按字典顺序进行的(按字典顺序排列(排序)的项的集合)。

现在,如果要为Lucene搜索操作实现RangeQuery ,则必须添加一个名为searchIndexWithRangeQuery() ,该方法基本上是一个构造函数,需要一个Term指示范围的开始,一个Term指示范围的结束和一个布尔值,指示搜索是包含开始和结束值(“ true”)还是排除开始和结束值(“ false”)。 代码看起来像

public static void searchIndexWithRangeQuery(String whichField, String start, String end, boolean inclusive)throws IOException, ParseException {System.out.println("\\nSearching for range '" + start + " to " + end + "' using RangeQuery");Directory directory = FSDirectory.getDirectory(INDEX_DIRECTORY);IndexSearcher indexSearcher = new IndexSearcher(directory);Term startTerm = new Term(whichField, start);Term endTerm = new Term(whichField, end);Query query = new RangeQuery(startTerm, endTerm, inclusive);Hits hits = indexSearcher.search(query);displayHits(hits);
}

现在我们将调用上述方法,

searchIndexWithRangeQuery(FIELD_LAST_MODIFIED, "2014-04-01-00-00-00", "2014-04-01-23-59-59", INCLUSIVE);searchIndexWithRangeQuery(FIELD_LAST_MODIFIED, "2014-04-02-00-00-00", "2014-04-02-23-59-59", INCLUSIVE);searchIndexWithRangeQuery(FIELD_LAST_MODIFIED, "2014-04-01-00-00-00", "2014-04-01-21-21-02", INCLUSIVE);searchIndexWithRangeQuery(FIELD_LAST_MODIFIED, "2014-04-01-00-00-00", "2014-04-01-21-21-02", EXCLUSIVE);// equivalent range searches using QueryParsersearchIndexWithQueryParser(FIELD_LAST_MODIFIED, "[2014-04-01-00-00-00 TO 2014-04-01-23-59-59]");searchIndexWithQueryParser(FIELD_LAST_MODIFIED, "[2014-04-02-00-00-00 TO 2014-04-02-23-59-59]");searchIndexWithQueryParser(FIELD_LAST_MODIFIED, "[2014-04-01-00-00-00 TO 2014-04-01-21-21-02]");searchIndexWithQueryParser(FIELD_LAST_MODIFIED, "{2014-04-01-00-00-00 TO 2014-04-01-21-21-02}");

最后, createIndex()方法稍有变化。 我们添加了一些实现日期时间的操作并打印了索引文件的最后修改时间。

在控制台输出的顶部,我们可以看到两个文件都已建立索引,并且这些文件的“最后修改”时间为“ 2014-04-01-21-21-02”(对于test-foods.txt )和“ 2014-04-01-21-21-38”(针对sample-foods.txt)。

在第一个范围查询中,我们搜索所有在2014年4月1日最后一次修改的文件。由于两个文件在该日期最后一次修改,这将返回2次匹配。 在第二个范围查询中,我们搜索所有在2014年4月2日最后一次修改的文件。由于两个文档都在2014年4月1日最后一次修改,因此返回0次匹配。

接下来,我们在2014年4月1日至2014年4月1日至2014年4月1日的范围内进行搜索。 由于test-foods.txt的上次修改时间为2014-04-01-21-21-02,并且范围查询包含此值,因此我们获得了一个搜索结果。 之后,我们仅在2014-04-01-00-00-00到2014-04-01-21-21-02之间进行搜索。 由于test-foods.txt的上次修改时间为2014-04-01-21-21-02,并且范围查询不包含此值(因为已将其排除在外),因此此搜索返回0个匹配。

此后,接下来的四个搜索显示使用QueryParser对象执行的等效搜索。 请注意,对于每个查询,QueryParser的parse()方法都返回ConstantScoreRangeQuery对象而不是RangeQuery对象,正如我们从这些查询的控制台输出中看到的那样。

4.6。前缀查询

与包含带有指定前缀的术语的文档匹配的QueryPrefixQueryQueryParser构建,用于类似nam *的输入。

我们将尝试使用两个文本文件(test-foods.txt和sample-foods.txt)通过前缀查询来搜索带有其前缀的特定术语。

对于这样做,我们将增加一个名为方法searchIndexWithPrefixQuery()将搜索器的索引(这将创建createIndex()使用PrefixQuery 。 此方法有两个参数,一个是字段名,另一个是搜索字符串。

public static void searchIndexWithPrefixQuery(String whichField, String searchString) throws IOException,ParseException {System.out.println("\\nSearching for '" + searchString + "' using PrefixQuery");Directory directory = FSDirectory.getDirectory(INDEX_DIRECTORY);IndexSearcher indexSearcher = new IndexSearcher(directory);Term term = new Term(whichField, searchString);Query query = new PrefixQuery(term);Hits hits = indexSearcher.search(query);displayHits(hits);
}

接下来,我们将从程序的main()方法中调用此方法–

searchIndexWithPrefixQuery(FIELD_CONTENTS, "test");searchIndexWithPrefixQuery(FIELD_CONTENTS, "tes*");

在第一个查询中,查询字符串不包含星号。 因此,如果我们打印QueryParser的parse()方法的查询类型,它将打印TermQuery而不是PrefixQuery

在第二查询中,星号向QueryParser指示这是一个前缀查询,因此它从其parse()方法返回PrefixQuery对象。 这导致在索引内容中搜索前缀“ tes”。 由于“ test”在索引中,因此产生1次匹配。

4.7。模糊查询

模糊查询基于Damerau-Levenshtein(最佳字符串对齐)算法。 FuzzyQuery将术语“接近”匹配到指定的基本术语:我们指定了一个允许的最大编辑距离,并且在与基本术语(然后包含这些术语的文档)相距该编辑距离内的所有术语都匹配。

QueryParser语法是QueryParserQueryParser ,其中N是允许的最大编辑数量(对于较早的发行版,N是0.0到1.0之间的令人困惑的浮点数,它通过一个棘手的公式转换为等效的最大编辑距离)。

FuzzyQuery非常适合匹配专有名称:我们可以搜索lucene〜1,它将匹配luccene(插入c),lucee(删除n),lukene(用k替换c)和许多其他“接近”术语。 使用最大编辑距离2,我们最多可以有2个插入,删除或替换。 每次比赛的得分均基于该词的编辑距离; 因此完全匹配的得分最高; 编辑距离1,降低; 等等

QueryParser支持在词条上使用尾随波浪号的模糊词条查询。 例如,搜索wuzza〜将找到包含“ fuzzy”和“ wuzzy”的文档。 编辑距离会影响得分,例如,较低的编辑距离会得分较高。

翻译自: https://www.javacodegeeks.com/2015/09/advanced-lucene-query-examples.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/357136.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue 路由的基本使用

目录 Vue.js 路由 安装 直接下载 / CDN NPM to replace append tag

【Egret】Wing3发布移动APP功能,打包APK流程以及会遇到的问题

流程&#xff1a;1.安装好wing 3&#xff0c;然后 插件——Egret项目工具——发布移动APP——Build android native project 2.配置发布环境&#xff1a; Android 1.egret engine 点击下载2.android sdk mac版下载 windows版下载3.java sdk mac版下载 windows版…

Vue过渡 动画混入

目录 过渡 自定义过渡的类名 同时使用过渡和动画 显性的过渡持续时间

有效运维的 on-call 机制

[编者按]本文作者为云告警平台OneAlert负责人&#xff0c;著《云计算与OpenStack》&#xff0c;在IT运营管理、云计算方面从业10多年。 正文 互联网技术的发展&#xff0c;离不开运维支撑工作&#xff0c;没有零bug的程序&#xff0c;没有不出问题的系统&#xff0c;问题故障不…

vue中Ajax(axios)及Ajax(vue-resource)的使用方法

目录 Vue.js Ajax(axios) GET 方法 请求方法的别名 并发 请求配置项 响应结

javafx11 最佳实践_JavaFX移动应用程序最佳实践,第2部分

javafx11 最佳实践警告&#xff1a;我在这里给出的提示适用于JavaFX Mobile的当前版本&#xff0c;该版本是JavaFX 1.1 SDK的一部分。 在将来的版本中&#xff0c;行为将发生变化&#xff0c;上述工件的当前不良性能将被优化或至少得到显着改善。 我在这里写的所有内容都是快照…

团队项目:界面设计

游戏内关卡为2D横版界面&#xff0c;背景为楼群贴图&#xff0c;整体色调以灰色为主&#xff0c;与摩托车手的主题相配。游戏中配有音效及背景音乐&#xff0c;背景音乐为我组成员自行创作录制完成。界面展示如下&#xff1a; 图1 游戏中设计图 图中显示的摩托车手即为玩家操控…

vues响应接口and实例

目录 Vue.js 响应接口 Vue.set Vue.delete Vue.js 实例 导航菜单实例 编辑文本实例

Hystrix简介

在过去的几天里&#xff0c;我一直在探索Netflix Hystrix库&#xff0c;并欣赏了这个出色的库所提供的功能。 引用Hystrix网站上的内容&#xff1a; Hystrix是一个延迟和容错库&#xff0c;旨在隔离对远程系统&#xff0c;服务和第三方库的访问点&#xff0c;停止级联故障&am…

MP3音乐播放器搜索引擎-鼠标拖动窗口

定义鼠标的按压&#xff0c;移动&#xff0c;施放事件 &#xff08;1&#xff09;鼠标的按压事件 globalpos是全局坐标&#xff0c;即鼠标相对于桌面屏幕左上角的坐标我们通过this->frameGeometry().topLeft();可以获得当前窗口的左上角的x左边或y坐标 在移动事件中我们可以…

SpringMVC学习--文件上传

简介文件上传是web开发中常见的需求之一&#xff0c;springMVC将文件上传进行了集成&#xff0c;可以方便快捷的进行开发。 springmvc中对多部件类型解析在 页面form中提交enctype"multipart/form-data"的数据时&#xff0c;需要springmvc对multipart类型的数据进行解…

VS code常用的快捷键

在前端的开发过程中&#xff0c;如果有一个比较好的开发工具&#xff0c;配合一些常用的快捷键&#xff0c;开发效率将大大提升&#xff0c;正所谓工具善其事必先利其器。前端推荐使用编辑器VS code,用过HB-X&#xff0c;ST3,Webstorm等编译器之后就会发现&#xff0c;前端编辑…

平台日志架构说明log4j漏洞问题解析

Log4j是Apache的一个开源项目&#xff0c;通过使用Log4j&#xff0c;我们可以控制日志信息输送的目的地是控制台、文件、GUI组件&#xff0c;甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等&#xff1b;我们也可以控制每一条日志的输出格式&#xff1b;通过定义每…

2016/06/22 中色启动筹码分析作业

2016/06/22 中色启动筹码分析作业——待核实 201转载于:https://www.cnblogs.com/carl2380/p/5608596.html

让我们暂停一微秒

低延迟Java应用程序中的许多基准测试涉及必须在一定负载下测量系统。 这就要求保持事件进入系统的稳定吞吐量&#xff0c;而不是在没有任何控制的情况下以全油门将事件泵入系统。 我经常要做的任务之一是在事件之间暂停生产者线程一小段时间。 通常&#xff0c;此时间量为个位…

浏览器各个属性的作用

作为前端程序员不可避免的会和浏览器打交道&#xff0c;所以要对浏览器的各个属性的作用进行了解&#xff0c;方便开发及调试&#xff0c;这里以谷歌浏览器为例进行简单的介绍。一是巩固对浏览器属性的认识&#xff0c;二是方便大家的学习。首先打开谷歌浏览器按F12查看控制台属…

Moment.js日期处理库的使用

Moment.jsMoment.js是一个轻量级的JavaScript时间库&#xff0c;它方便了日常开发中对时间的操作&#xff0c;提高了开发效率。这个在一些金融保险公司会经常用到&#xff0c;比如一下时间的格式化处理&#xff0c;时间的选择等等。这个比较好的地方是可以格式化时间&#xff0…

spring ldap_Spring 3,Spring Web Services 2和LDAP安全

spring ldap今年的开局很好&#xff0c;其中另一个“截止日期不会改变” /“跳过所有繁文tape节” / “狂野西部”类型的项目中&#xff0c;我必须弄清楚并使用相对而言实现一些功能。新的库和技术需要进行更改&#xff0c;Spring 3并不是新增功能&#xff0c;但是在Java 5&…

转: 微博的多机房部署的实践(from infoq)

转: http://www.infoq.com/cn/articles/weibo-multi-idc-architecture 在国内网络环境下&#xff0c;单机房的可靠性无法满足大型互联网服务的要求&#xff0c;如机房掉电&#xff0c;光缆被挖的情况也发生过。微信就曾发生大面积故障&#xff0c;包括微信信息无法发出、无法刷…

知道这些性能优化手段,工资起码提升一倍

1.什么是性能?性能指标有哪些&#xff1f;计算机的性能&#xff0c;其实和我们干体力劳动很像&#xff0c;好比是我们要搬东西。对于计算机的性能&#xff0c;我们需要有个标准来衡量。这个标准中主要有两个指标。第一个是响应时间&#xff08;Response time&#xff09;或者叫…