lucene 查询示例_Lucene查询(搜索)语法示例

本文详细介绍了Apache Lucene的基本查询机制,包括术语查询、短语查询、布尔查询、通配符查询、RegexpQuery、TermRangeQuery、NumberRangeQuery和模糊查询。通过实例展示了如何使用这些查询类进行高效搜索,帮助开发者更好地理解和应用Lucene。
摘要由CSDN通过智能技术生成

lucene 查询示例

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

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

1.简介

在本课程的这一课中,我们将研究Lucene提供的基本查询机制。 您可能会在入门课程中记得,Lucene不会将要搜索的原始文本发送到索引。 为此,它使用Query对象。 在本课程中,我们将看到所有关键要素,它们将人类书面搜索短语转换为诸如Queries类的代表性结构。

2.查询类

Query类是一个公共抽象类,它代表对索引的查询。 在本节中,我们将看到最重要的Query子类,您可以使用它们来执行高度定制的查询。

2.1术语查询

这是您可以针对Lucene索引执行的最简单直接的查询。 您只需搜索在特定Field包含单个单词的Documents

基本的TermQuery构造函数定义如下: public TermQuery(Term t) 。 您从第一节课中记得, Term由两部分组成:

  1. 该术语所驻留的Field的名称。
  2. 术语的实际值,在大多数情况下,是通过对某些纯文本的分析得出的单个单词。

因此,如果您想创建一个TermQuery来查找所有在"content" Field中包含"good"字样的Documents ,则可以按照以下方法进行操作

TermQuery termQuery = new TermQuery(new Term("content","good"));

我们可以使用它在先前创建的索引中搜索单词“ static”:

String q = "static"

Directory directory = FSDirectory.open(indexDir);

IndexReader  indexReader  = DirectoryReader.open(directory);

IndexSearcher searcher = new IndexSearcher(indexReader);

Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_46);

TermQuery termQuery = new TermQuery(new Term("content",q));

TopDocs topDocs =searcher.search(termQuery, maxHits);

ScoreDoc[] hits = topDocs.scoreDocs;

for (ScoreDoc hit : hits) {
        int docId = hit.doc;
        Document d = searcher.doc(docId);
        System.out.println(d.get("fileName") + " Score :" + hit.score);
}

System.out.println("Found " + hits.length);

输出为:

C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\Product.java Score :0.29545835
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\SimpleSearcher.java Score :0.27245367
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\PropertyObject.java Score :0.24368995
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\SimpleIndexer.java Score :0.14772917
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\TestSerlvet.java Score :0.14621398
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\ShoppingCartServlet.java Score :0.13785185
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\MyServlet.java Score :0.12184498
Found 7

如您所见,我的七个源文件中包含"static"关键字。 就是这样。 自然,如果您尝试在查询字符串中添加另一个单词,搜索将返回0个结果。 例如,如果您将查询字符串设置为:

String q = "private static"

输出为:

Found 0

现在,我知道我的许多源文件中都存在"private static" 。 但是,您可能还记得,我们在索引过程中使用了StandarAnalyzer处理从文件中检索的纯文本。 StandardAnalyzer将文本拆分为单个单词,因此每个Term包含一个单词。 您可以选择不标记索引的Field 。 但是我建议您在包含元数据的Fields中执行此操作,而不是在包含其内容的字段中,这些字段包含有关文档的信息(例如标题或作者)。 例如,如果您选择不对名称为'author'且值为'James Wilslow'Field进行标记化并编制索引,则Field 'author'将仅包含一个整体值为'James Wilslow' Term 。 如果您对Field进行了标记化,则它将包含两个Terms ,一个的值为'James' ,另一个的值为'Wilslow'

2.2短语查询

使用PhraseQuery您可以搜索包含特定单词序列(又名短语)的Documents

您可以这样创建一个PhraseQuery

PhraseQuery phraseQuery = new PhraseQuery();

然后您可以向其添加Terms 。 例如,如果您要搜索在其“内容”字段中包含短语“ private static”的Documents ,则可以这样做:

PhraseQuery phraseQuery = new PhraseQuery();

phraseQuery.add(new Term("content","private"));
phraseQuery.add(new Term("content","static"));

TopDocs topDocs =searcher.search(phraseQuery, maxHits);

ScoreDoc[] hits = topDocs.scoreDocs;

for (ScoreDoc hit : hits) {
      int docId = hit.doc;
      Document d = searcher.doc(docId);
      System.out.println(d.get("fileName") + " Score :" + hit.score);
}

System.out.println("Found " + hits.length);

输出为:

C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\Product.java Score :0.54864377
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\PropertyObject.java Score :0.45251375
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\SimpleSearcher.java Score :0.45251375
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\TestSerlvet.java Score :0.27150828
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\ShoppingCartServlet.java Score :0.25598043
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\MyServlet.java Score :0.22625688
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\SimpleIndexer.java Score :0.22398287
Found 7

仅当“ Field "static"连续且以准确顺序同时包含单词"private""static"Document才进入结果。

因此,如果您以上述方式更改上面的代码:

phraseQuery.add(new Term("content","private"));
phraseQuery.add(new Term("content","final"));

你会得到 :

Found 0

这是因为尽管我的源文件包含两个词,但它们不是连续的。 要改变这种行为一点点,你可以添加一个slopPhraseQuery 。 当斜率增加1时,您最多允许一个词插入词组中的词之间。 添加坡度2时,短语中的单词之间最多允许2个单词。

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

因此,如果这样做:

PhraseQuery phraseQuery = new PhraseQuery();

phraseQuery.add(new Term("content","private"));
phraseQuery.add(new Term("content","final"));

phraseQuery.setSlop(2);

我们的搜索输出将给出:

C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\Product.java Score :0.38794976
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\PropertyObject.java Score :0.31997555
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\SimpleSearcher.java Score :0.31997555
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\TestSerlvet.java Score :0.19198532
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\ShoppingCartServlet.java Score :0.18100551
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\MyServlet.java Score :0.15998778
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\SimpleIndexer.java Score :0.15837982

重要的是要提到包含更接近查询确切短语的短语的文档将获得更高的分数。

2.3布尔查询

BooleanQuery是一种更具表现力和功能的工具,因为您可以将多个查询与布尔子句结合在一起。 可以使用BooleanClauses填充BoleanQuery。 BooleanClause包含一个Query ,以及Query在布尔搜索中应具有的角色。

更具体地说,布尔子句可以在查询中扮演以下角色:

  1. MUST :这是自我explenatory 。 当且仅当Document包含该子句时,它才会进入结果列表。
  2. MUST NOT :这是完全相反的情况。 对于文档而言,必须将其包含在结果列表中,而不包含该子句。
  3. SHOULD :这是针对Document中可能出现的子句的,但是为了使结果成为结果,它们没有必要包含这些子句。

如果仅使用SHOULD子句进行布尔查询,则结果至少匹配其中一个子句。 这看起来像经典的OR布尔运算符,但正确使用它并不是那么简单。

现在让我们看一些例子。 让我们找到包含单词“ string”但不包含单词“ int”的源文件。

TermQuery termQuery = new TermQuery(new Term("content","string"));
TermQuery termQuery2 = new TermQuery(new Term("content","int"));

BooleanClause booleanClause1 = new BooleanClause(termQuery, BooleanClause.Occur.MUST);
BooleanClause booleanClause2 = new BooleanClause(termQuery2, BooleanClause.Occur.MUST_NOT);

BooleanQuery booleanQuery = new BooleanQuery();
booleanQuery.add(booleanClause1);
booleanQuery.add(booleanClause2);

TopDocs topDocs =searcher.search(booleanQuery, maxHits);

结果如下:

C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\SimpleEJB.java Score :0.45057273
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\PropertyObject.java Score :0.39020744
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\ShoppingCartServlet.java Score :0.20150226
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\TestSerlvet.java Score :0.13517183
Found 4

现在,让我们尝试查找包含单词“ nikos”和短语“ httpservletresponse response”的所有文档。 在以下代码片段中,您可以看到如何避免创建BooleanClause实例,从而使您的代码更紧凑。

TermQuery termQuery = new TermQuery(new Term("content","nikos"));

PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.add(new Term("content","httpservletresponse"));
phraseQuery.add(new Term("content","response"));

BooleanQuery booleanQuery = new BooleanQuery();

booleanQuery.add(phraseQuery,BooleanClause.Occur.MUST);
booleanQuery.add(termQuery,BooleanClause.Occur.MUST);

TopDocs topDocs =searcher.search(booleanQuery, maxHits);

结果如下:

C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\ShoppingCartServlet.java Score :0.3148332
Found 1

让我们找到所有包含单词“ int”或单词“ nikos”的文档。当您可能要成像时,必须以某种方式使用SHOULD规范:

TermQuery termQuery = new TermQuery(new Term("content","int"));
TermQuery termQuery2 = new TermQuery(new Term("content","nikos"));

BooleanQuery booleanQuery = new BooleanQuery();

booleanQuery.add(termQuery,BooleanClause.Occur.SHOULD);
booleanQuery.add(termQuery2,BooleanClause.Occur.SHOULD);

TopDocs topDocs =searcher.search(booleanQuery, maxHits);

这虽然不太困难,但是创建更复杂的析取查询有点棘手。 如何正确使用它并不总是那么简单。

例如,让我们尝试查找所有包含单词“ nikos”和短语“ httpservletresponse response”或单词“ int”的文档。 一个人可以这样写:

TermQuery termQuery = new TermQuery(new Term("content","nikos"));

PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.add(new Term("content","httpservletresponse"));
phraseQuery.add(new Term("content","response"));

BooleanQuery booleanQuery = new BooleanQuery();

booleanQuery.add(phraseQuery,BooleanClause.Occur.MUST);
booleanQuery.add(termQuery,BooleanClause.Occur.MUST);
booleanQuery.add(new TermQuery(new Term("content","int")),BooleanClause.Occur.SHOULD);

TopDocs topDocs =searcher.search(booleanQuery, maxHits);

但是查询将无法提供所需的结果。 请记住,如我们所构造的那样,此查询的结果必须同时包含单词"nikos"并且必须同时包含短语"httpservletresponse response" 。 但这不是您想要的。 您需要包含nikos单词和短语"httpservletresponse response"文档,但也希望独立包含单词"int"文档,无论它们是否包含其他子句。 公平地说,上述布尔查询有点错误。 因为用直接的布尔语法,您永远都不会这样写:A AND B ORC。您应该写(A AND B)ORC。或者A AND(B OR C)。 看到不同?

因此,您应该编写所需的查询:(“ nikos”和“ httpservletresponse response”)或“ int”。

您可以将BooleanQueries组合在一起。 使用上面严格的语法,很难想象这将如何进行:

TermQuery termQuery = new TermQuery(new Term("content","nikos"));

PhraseQuery phraseQuery = new PhraseQuery();
phraseQuery.add(new Term("content","httpservletresponse"));
phraseQuery.add(new Term("content","response"));

// (A AND B)
BooleanQuery conjunctiveQuery = new BooleanQuery();
conjunctiveQuery.add(termQuery,BooleanClause.Occur.MUST);
conjunctiveQuery.add(phraseQuery,BooleanClause.Occur.MUST);

BooleanQuery disjunctiveQuery = new BooleanQuery();

// (A AND B) OR C
disjunctiveQuery.add(conjunctiveQuery,BooleanClause.Occur.SHOULD);
disjunctiveQuery.add(new TermQuery(new Term("content","int")),BooleanClause.Occur.SHOULD);

TopDocs topDocs =searcher.search(disjunctiveQuery, maxHits);

这是使用BooleanQuery类构造布尔查询时可以遵循的快速指南:

  • X和Y
BooleanQuery bool = new BooleanQuery();
bool.add(X,BooleanClause.Occur.MUST);
bool.add(Y,BooleanClause.Occur.MUST);
  • X或Y
  • BooleanQuery bool = new BooleanQuery();
    bool.add(X,BooleanClause.Occur.SHOULD);
    bool.add(Y,BooleanClause.Occur.SHOULD);
  • X AND(不是Y)
  • BooleanQuery bool = new BooleanQuery();
    bool.add(X,BooleanClause.Occur.MUST);
    bool.add(Y,BooleanClause.Occur.MUST_NOT);
  • (X和Y)或Z
  • BooleanQuery conj = new BooleanQuery();
    
    conj.add(X,BooleanClause.Occur.MUST);
    conj.add(Y,BooleanClause.Occur.MUST);
    
    BooleanQuery disj = new BooleanQuery();
    disj.add(conj,BooleanClause.Occur.SHOULD)
    disj.add(Z,BooleanClause.Occur.SHOULD)
  • (X或Y)和Z
  • BooleanQuery conj = new BooleanQuery();
    
    conj.add(X,BooleanClause.Occur.SHOULD);
    conj.add(Y,BooleanClause.Occur.SHOULD);
    
    BooleanQuery disj = new BooleanQuery();
    disj.add(conj,BooleanClause.Occur.MUST)
    disj.add(Z,BooleanClause.Occur.MUST)
  • X或(非Z)
  • BooleanQuery neg = new BooleanQuery();
    
    neg.add(Z,BooleanClause.Occur.MUST_OT);
    
    BooleanQuery disj = new BooleanQuery();
    disj.add(neg,BooleanClause.Occur.SHOULD)
    disj.add(X,BooleanClause.Occur.SHOULD)

    上面的代码可用于创建越来越复杂的布尔查询。

    2.4通配符查询

    顾名思义,您可以使用WildcardQuery类使用“ *”或“?”执行通配符查询。 字符。 例如,如果要o搜索包含以'ni'开头的词条,然后是其他任何字符序列的文档,则可以搜索'ni *'。 如果要搜索以“ jamie”开头(后接(任意)一个字符)的术语,则可以搜索“ jamie?”。 就那么简单。 自然地, WildcardQueries效率低下,因为搜索可能要经过很多不同的术语才能找到匹配项。 通常,最好避免将通配符放在单词的开头,例如“ * abcde”。

    让我们来看一个例子:

    Query wildcardQuery = new WildcardQuery(new Term("content","n*os"));
    TopDocs topDocs =searcher.search(wildcardQuery, maxHits);

    Query wildcardQuery = new WildcardQuery(new Term("content","niko?"));
    TopDocs topDocs =searcher.search(wildcardQuery, maxHits);

    2.5 RegexpQuery

    使用RegexpQuery ,您可以执行快速的正则表达式查询,并通过Lucene的快速自动机实现对其进行评估。 这是一个例子

    Query regexpQuery = new RegexpQuery(new Term("content","n[a-z]+"));
    
    TopDocs topDocs =searcher.search(regexpQuery, maxHits);

    2.6 TermRangeQuery

    当对字符串术语执行范围查询时,此查询子类很有用。 例如,您可以搜索“ abc”和“ xyz”两个词之间的字词。 字的比较是使用Byte.compareTo(Byte)执行的。 您可能会发现这对于在文档元数据中进行范围查询(例如标题甚至日期)特别有用(如果使用日期,请小心使用DateTools )。

    以下是查找上周创建的所有文档的方法:

    Calendar c = Calendar.getInstance();
    c.add(Calendar.DATE, -7);
    Date lastWeek = c.getTime();
    
    Query termRangeQuery = TermRangeQuery.newStringRange("date", DateTools.dateToString(new Date(), DateTools.Resolution.DAY),DateTools.dateToString(lastWeek, 
    
    DateTools.Resolution.DAY),true,true);

    当然,在为“日期”字段建立索引时必须小心。 您还必须将DateTools.dateToString应用于它,并指定不进行分析的字段(这样就不会标记化该字段并将其拆分为单词)。

    2.7 NumberRangeQuery

    这用于执行数字范围查询。 想象一下,您有一个“ wordcount”字段,用于存储该文档的单词数,并且您要检索的单词数在2000到10000之间:

    Query numericRangeQuery = NumericRangeQuery.newIntRange("wordcount",2000,10000,true,true);

    布尔参数指示范围内包括上限和下限。

    2.8模糊查询

    这是一个非常有趣的查询子类。 该查询根据邻近度量(例如众所周知的Damerau-Levenshtein距离)评估字词。 这将找到词典顺序接近的单词。 如果您想执行复杂的词典应用程序,例如词典或“您要说的话”字词建议功能,则可以使用SpellChecker API

    让我们看看如何执行不幸的“字符串”拼写错误的模糊查询搜索:

    Query fuzzyQuery = new FuzzyQuery(new Term("content","srng"));

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

    lucene 查询示例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值