lucene 查询示例_高级Lucene查询示例

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 将其他Query实例聚合为允许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 ,并且与第五个查询一样,它获得成功。
  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()方法,该方法采用两个字符串表示文档中的单词和searchIndexWithPhraseQuery()值。 它通过基于“ 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年)之间进行搜索。 由于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

lucene 查询示例

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

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

相关文章

okhttp 连接池_okhttp 源码分析

https://square.github.io/okhttp/​square.github.iosquare/okhttp​github.com0 概述okhttp是一个现代的网络请求框架Http/2 支持 所有访问同一个主机的Request都共用一个socketconnection pool 连接池 减少请求延迟GZIP 压缩数据&#xff0c;减少传输所用的带宽Response Cac…

程序员日均写7行代码被开除,公司:正常员工每天200行

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删根据前不久CSDN发布的《2021-2022中国开发者调查报告》显示&#xff0c;大部分程序员平均每天会写200行左右的代码。那么代码的数量能衡量一个程…

抽象工厂和工厂方法示例_工厂方法设计模式示例

抽象工厂和工厂方法示例本文是我们名为“ Java设计模式 ”的学院课程的一部分。 在本课程中&#xff0c;您将深入研究大量的设计模式&#xff0c;并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因&#xff0c;并了解何时以及如何应用模式中的每一个。 在这里查…

rust废铁最快_Rust初体验,它确实有点快

写了多年的Java&#xff0c;某天机缘巧合之下听说了一门语言叫Rust&#xff0c;Rust的亲爹是Mozilla&#xff0c;如果要和其它语言拼爹的话&#xff0c;实力应该还是可以的。官方介绍如下&#xff1a;Rust is blazingly fast and memory-efficient: with no runtime or garbage…

jax-ws和jax-rs_JAX-RS和JSON-P集成

jax-ws和jax-rs这篇简短的文章讨论了JAX-RS 2.0中对JSON-P的支持 JSON-P…&#xff1f; JSON处理API &#xff08;JSON-P&#xff09;是Java EE 7中引入的。 它提供了用于处理JSON数据的标准API&#xff0c;并且与XML对应的JAXP非常相似。 JSON-B &#xff08;JSON绑定&#x…

这10个C语言技巧让初学者少走180天弯路!

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删技巧 1&#xff1a;不要使用“GOTO”语句二十几年前&#xff0c;当计算机编程尚处于起步阶段时&#xff0c;程序流程是由“GOTO”语句来控制。该…

flyway版本号_Flyway版本化管理数据库脚本

假如我们有一个叫shiny的项目&#xff0c;它是由一个程序Shiny-Server 和一个数据库 Shiny-DB组成的;简单结构图如下&#xff1a;image.png但是很多时候&#xff0c;现实开发团队是这样的&#xff1a;image.png我们的项目shiny项目的运行环境是有多套的&#xff0c;我们擅长解决…

hystrix熔断 简介_Hystrix简介

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

89 个嵌入式相关概念,你懂几个?

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删01操作系统&#xff08;Operating System&#xff0c;OS&#xff09;是管理计算机硬件与软件资源的系统软件&#xff0c;同时也是计算机系统的内…

python源码笔记_python源码学习笔记(二)

(二) python 继承和多态这非常类似C的功能&#xff0c;只不过是是在C基础上开发的。由上一节知&#xff0c;python的所有对象的基础都是PyObject&#xff0c;所以例如创建一个PyIntObject对象&#xff0c;是通过PyObejct*变量来维护&#xff0c;所以在python内部各个函数之间传…

linux 延时一微秒_让我们暂停一微秒

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

C语言不是最好的,却是我最爱的~

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删以下为译文&#xff1a;虽然 C 语言并不是我所学的第一门语言&#xff0c;也不是我的最后一门语言&#xff0c;但是我仍然非常喜欢 C&#xff0c…

vue 传递多行数据_vue父组件向子组件传递多个数据的实例

在平时我们使用VUE组件的时候&#xff0c;经常需要将父组件的某些数据传递给子组件&#xff0c;这个时候&#xff0c;我们通常会有很多的办法&#xff0c;这里主要分为两种情况&#xff1a;第一种&#xff1a;静态数据传递&#xff1a;传递一个 字符串第二种&#xff1a;动态数…

lucene 源码分析_Lucene分析过程指南

lucene 源码分析本文是我们名为“ Apache Lucene基础知识 ”的学院课程的一部分。 在本课程中&#xff0c;您将了解Lucene。 您将了解为什么这样的库很重要&#xff0c;然后了解Lucene中搜索的工作方式。 此外&#xff0c;您将学习如何将Lucene Search集成到您自己的应用程序中…

ggplot2箱式图两两比较_R语言进阶笔记2 | 长数据与ggplot2

1. 长数据是什么鬼&#xff1f;之前介绍了如何将多个性状的箱线图放在一个图上&#xff0c;比如learnasreml包中的fm数据&#xff0c;它有h1~h5五年的株高数据&#xff0c;想对它进行作图。「数据预览&#xff1a;」> library(learnasreml)> data(fm)> head(fm) Tree…

面向对象,C语言实现简单工厂模式,思路+代码

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删1、简介简单工厂方法定义一个用于创建对象的类&#xff0c;该类接受一个参数&#xff0c;通过参数决定创建不同的对象。GOF并没有把简单工厂方法…

javaone_JavaOne和OOW 2015总结

javaone大家好&#xff01; 终于&#xff0c;我回来了一个很棒的JavaOne和OOW2015。在这篇文章中&#xff0c;我想分享我的经验&#xff0c;一些照片和我参加的演讲的摘要。 会议前 我于2015年6月24日星期六乘Copa航空公司CLO-PTY-SFO飞往旧金山。 从哥伦比亚出发&#xff08;…

如何导出久其报表所有数据_如何选择好的HR软件

相信HR朋友想要换HR系统的时候&#xff0c;一般都会在百度、360和搜狗上找&#xff0c;或者通过朋友介绍&#xff0c;而自己百度找的时候&#xff0c;就会出现很多HR软件的广告&#xff0c;一个一个的去问&#xff0c;也不一定能问出所以然&#xff0c;所以就约着面谈&#xff…

网站快速变灰色,几行代码就搞定了!

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删自从伟大的江爷爷走了后&#xff0c;全站和各个App的内容都变成了灰色&#xff0c;包括按钮、图片等等。这时候我们可能会好奇这是怎么做到的呢&…

java 递归 堆栈_Java中的堆栈安全递归

java 递归 堆栈在本文中&#xff0c;摘自《 Java中的函数编程 》一书&#xff0c;我解释了如何使用递归&#xff0c;同时避免了StackOverflow异常的风险。 Corecursion正在使用第一步的输出作为下一步的输入来构成计算步骤。 递归是相同的操作&#xff0c;但是从最后一步开始。…