搜索过程

图解:

主要 API:

  • IndexSearcher:    //所有搜索都通过 IndexSearcher 进行,他们将调用该类中重载的 search() 方法
  • Query:            //封装某种查询类型的具体子类,Query 实例将会被传递给 IndexSearcher 的 search() 方法
  • QueryParser:      //将用户输入的查询表达式处理成各种具体的 Query 对象
  • TopDocs:          //保存由 IndexSearcher.search() 方法返回的具有较高评分的文档
  • ScoreDoc:         //提供对 TopDocs 中每条搜索结果的访问接口

下面,将对这几类 API 做分别的讨论。

使用IndexSearcher类

//  创建 IndexSearcher 类实例:
    Directory dir          = FSDirectory.open(/path/to/indices);
    IndexReader reader     = IndexReader.open(dir);
    IndexSearcher searcher = new IndexSearcher(reader);
//  实现搜索功能 IndexSearcher.search():
    TopDocs search(Query query, int n)                                 //————直接进行搜索,返回评分最高的N个文档
    TopDocs search(Query query, Filter filter, int n)                  //————搜索受文档子集约束,约束条件基于过滤条件
    TopFieldDocs search(Query query, Filter filter, int n, Sort sort)  //————排序
    void search(Query query, Collector results)                        //————使用自定义文档访问策略
    void search(Query query, Filter filter, Collector results)

使用TopDocs类

调用 IndexSearcher.search() 方法,返回 TopDocs 对象。

    TopDocs.totalHits()          //匹配搜索条件的文档数量
    TopDocs.scoreDocs()          //包含搜索结果的ScoreDoc对象数组
    TopDocs.getMaxScore()        //如果已完成排序这返回最大评分

使用 Query 类

使用 Query 类就是直接使用 Lucene 的各种 Query API 来进行查询。

Query 的子类可以直接实例化,也可以通过 QueryParser 类实例化。通过 QueryParser 实例化会首先将自由文本转换为各种 Query 类型,这个将在【使用 QueryParser 类】 小节讲述。

TermQuery:

该查询是区分大小写的,搜索前要对索引后的项大小写进行匹配

  TermQuery:
    //该查询是区分大小写的,搜索前要对索引后的项大小写进行匹配
    Term t = new Term("contents", "java");
    Query query = new TermQuery(t);

TermRangeQuery:

索引中的各个 Term 回想会按照字典编排排序,并允许在 Lucene 的 TermQuery 对象提供的范围内进行文本项的直接搜索。

用两个Boolean对象参数表示是否包含搜索范围的起点/终点。

  TermRangeQuery:
    //用两个Boolean对象参数表示是否包含搜索范围的起点/终点
    TermRangeQuery query = new TermRangeQuery("title2", "d", "j", true, true);  //搜索 title 域起始字母从 'd' 到 'j' 的文档

NumericRangeQuery:

用两个Boolean对象参数表示是否包含搜索范围的起点/终点。

  NumericRangeQuery:
    //用两个Boolean对象参数表示是否包含搜索范围的起点/终点
    NumericRangeQuery query = new NumericRangeQuery.newIntRange("pubmonth", 200605, 200609, true, true);

PrefixQuery:

搜索包含以指定字符串开头的项的文档。

  PrefixQuery:
    //搜索包含以指定字符串开头的项的文档
    Term term = new Term("category", "/technology/computers/programing");
    PrefixQuery query = new PrefixQuery(term);  //搜索编程方面的书籍,包括他们的子类书籍(子目录)
    Query query = new TermQuery(term);          //搜索编程方面的书籍,不包括子类书籍(子目录)

BooleanQuery:

通过BooleanQuery可以将各种查询类型组合起来。

  BooleanQuery:
    //通过BooleanQuery可以将各种查询类型组合起来
    TermQuery searchingBooks = new TermQuery(new Term("subject", "search"));
    Query books2010 = NumericRangeQuery.newIntRange("pubmonth", 201001, 201009, true,true);
    BooleanQuery searchingBooks2010 = new BooleanQuery();

    searchingBooks2010.add(searchingBooks, BooleanClause.Occur.MUST);
    searchingBooks2010.add(books2010,BooleanClause.Occur.MUST)

PhraseQuery:

PhraseQuery类会根据项的位置信息定位某个距离范围内的项所对应的文档。

  PhraseQuery:
    //PhraseQuery类会根据项的位置信息定位某个距离范围内的项所对应的文档
    PhraseQuery query = new PhraseQuery();
    query.setSlop(slop);

WildcardQuery:

使用不完整的、缺少某些字母的项进行查询。

WildcardQuery:
  //使用不完整的、缺少某些字母的项进行查询
  Query query = new WildcardQuery(new Term("contents", "?ild*"));

FuzzyQuery:

用于查询与指定项相似的项(如:three/tree编辑距离为1)。

FuzzyQuery:
  //用于查询与指定项相似的项(three/tree编辑距离为1)
  Query query = new FuzzyQuery(new Term("contents", "wuzza"));

MatchAllDocsQuery:

MatchAllDocsQuery:
  Query query = new MatchAllDocsQuery();      //对匹配的分配固定的评分
  Query query = new MatchAllDocsQuery(field); //文档根据指定的域评分

使用 QueryParser 类

QueryParser 对象初始化

与 matchVersion、一个域名和一个分析器一起用于将输入的文本分割成 Terms 对象:

QueryParser parse = new QueryParser(Version.LUCENE_30, "contents", new SimpleAnalzer());

QueryParser 应用示例

      IndexSearcher searcher = new IndexSearcher(dir);
      QueryParser parse = new QueryParser(Version.LUCENE_30,"contents", new SimpleAnalzer());
      Query query = parser.parse("+JUNIT +ANT -MOCK"); //解析 "+JUNIT +ANT -MOCK" 为Query对象
      TopDocs docs = searcher.search(query, 10);

QueryParser 解析表达式

1. Query.toString:

  • 当查询表达式被解析为后会发生变化,通过 toString 方法可以查看解析后的语句。
//toString:
query.add(new FuzzyQuery(new Term("field", "kountry")), BooleanClause.Occur.MUST);
assertEquals("+kountry~0.5" query.toString(field));

2. 项查询:

  • 默认情况下,如果单个词不被识别为更长的其他查询类型表达式的一部分,那么将会被解析为 TermQuery 对象。
//TermQuery
QueryParse parser = new QueryParser(Version.LUCENE_30, "subject", analyzer);
Query query = parser.parse("computers"); //默认域
System.out.printfln("term: " + query);
//输出 term: subject:computers

3. 项范围查询:

  • 针对 "文本" 或 "日期" 的范围查询通过括号形式表示,并且只需要在查询范围两端的项之间用 TO(大写)进行连接就可以。
  • 用中括号:[]        表示搜索范围包含在内
  • 用大括号:{}        表示搜索范围排除在外
  • 这里和编程构建 TermRangeQuery 或 NumericRangeQuery 不同,搜索范围不能同时进行包含和排除,只能要么全部包含,要么全部排除。
//项范围查询
QueryParse parser = new QueryParser(Version.LUCENE_30, "subject", analyzer);
Query query = parser.parse("title2:[Q TO V]");
assertTrue(query instanceof TermRangeQuery);

Query query = parser.parse("title2:{Q TO \"Tapestry in action\"}");

4. 短语查询:

  • 查询语句中庸双引号括起来的项会被转换为 PhraseQuery 对象。在引号里面使用 "通配符" 将不会生效。
  • 单项短语对象将会被转换为 TermQuery 对象。
//短语查询
QueryParse parser = new QueryParser(Version.LUCENE_30, "field", new StandardAnalyzer(Version.LUCENE_30));
Query q = parser.parse("\"This is Some Phrase*\"");
assertEquals("analyzed", "\"? ? Some Phrase\"", q.toString("field"))

QueryParse parser = new QueryParser(Version.LUCENE_30, "field", analyzer);
Query q = parser.parse("\"term\"");
assertTrue("reduced to TermQuery", q instanceof TermQuery);

5. 布尔操作符:

  • 可以使用 AND、OR和NOT,布尔操作符必须全部大写。项之间如果没有指定布尔操作符,默认为 "OR"。
  • a AND b           快捷语法        +a +b
  • a OR b            快捷语法        ab
  • a AND NOT b       快捷语法        +a -b
//布尔操作符
QueryParse parser = new QueryParser(Version.LUCENE_30, "contents", analyzer);
parser.setDefaultOperator(QueryParser.AND_OPERATOR);

6. 前缀查询和通配符查询:

  • 如果某项中包含一个星号或者问好,该项会被看作是通配符查询对象 WildcardQuery。
  • 当查询只在末尾有一个星号时候,QueryParse 类会将它优化为前缀查询。
  • 不管是前缀还是通配符查询,其对象都会被转换为小写字母形式(可控)。
//前缀和通配符查询
QueryParse parser = new QueryParser(Version.LUCENE_30, "filed", analyzer);
Query query = parser.parse("prefixQuery*");
assertEquals("lowercased", "prefixQuery*", q.toString("field"))

7. 数值范围搜索和日期范围搜索:

  • QueryParser 类不会建立 NumericRangeQuery 类。

8. 模糊查询:

QueryParse parser = new QueryParser(Version.LUCENE_30, "subject", analyzer);
Query q = parser.parse("kountry~");
System.out.printfln("fuzzy: " + query);
// fuzzy: subject:kountry~0.5
query = parser.parse("kountry~0-7");
System.out.printfln("fuzzy 2: " + query);
// fuzzy: subject:kountry~0.7

9. MatchAllDocsQuery:

  • 当输入*:*后会被分析为 MatchAllDocsQuery

10. 分组查询:

  • QueryParser 使用分组后的文本类型的查询表达式来支持嵌套 。
//QueryParser 使用分组后的文本类型的查询表达式来支持嵌套 BooleanQuery 子句查询
QueryParse parser = new QueryParser(Version.LUCENE_30, "subject", analyzer);
Query q = parser.parse("(agile OR extreme) AND methodology");

11. 域选择:

  • 默认域名是在创建 QueryParser 时候创建。
  • 如果使用域选择器表示法,可以对非默认域中的项进行指定。

12. 对子查询设置加权:

  • 在浮点数前面加上一个^符号可以对查询进行加权因子设置。
  • junit^2.0 testing 会将 junit TermQuery 的加权系数设置为2.0;并维持 testing TermQuery 为默认1.0。
   java                                  //————默认域包括 java 项的文档
   java junit                            //————默认域包括 java 和 junit 中一个或两个项的文档
   java OR junit                         //————默认域包括 java 和 junit 中一个或两个项的文档
   +java +junit                          //————默认域包括 java 和 junit 两项的文档
   title:java                            //————title 域中包含 ant 项的文档
   title:extreme -subject:sports         //————title 域中包含 extreme 且 subject 域中不包含 sports 的文档
   tielt:extreme AND NOT subject:sports  //————title 域中包含 extreme 且 subject 域中不包含 sports 的文档
   (agile OR extreme) AND methodogy      //————默认域中包含 methodogy 且包含 agile 和 extreme 中一个或两个的文档
   title:"junit in action"               //————title 域为 junit in action 的文档
   title:"junit action" -5               //————title 域中junit 和 action之 间距离小于5的文档
   java*                                 //————包含由 java 开头的文档
   java-                                 //————包含与单词 java 相近的单词
   lastmodified:[1/1/09 TO 12/31/09]     //————lastmodified 域值在这个时间区间的文档

QueryParser 特殊字符

QueryParse 在各个项中使用反斜杠来表示转义,需要转义的字符有:

\
+
-
!
(
)
:
^
]
{
}
_
*
?

搜索结果分页

将首次搜索获得的多页结果手机起来保存在 ScoreDocs 和 IndexSearcher 实例中。

每次用户换页浏览时候都重新进行查询操作

近实时搜索

使用一个打开的 IndexWriter 快速搜索索引的变更内容,而不必首先关闭 writer 或向该 writer 提交。

Lucene 搜索功能的更多相关文章

  1. 【Lucene3.6.2入门系列】第03节_简述Lucene中常见的搜索功能

    package com.jadyer.lucene; import java.io.File; import java.io.IOException; import java.text.SimpleD ...

  2. Lucene5.5.4入门以及基于Lucene实现博客搜索功能

    前言 一直以来个人博客的搜索功能很蹩脚,只是自己简单用数据库的like %keyword%来实现的,所以导致经常搜不到想要找的内容,而且高亮显示.摘要截取等也不好实现,所以决定采用Lucene改写博客 ...

  3. Lucene搜索方式大合集

    package junit; import java.io.File; import java.io.IOException; import java.text.ParseException; imp ...

  4. lucene 搜索demo

    package com.ljq.utils; import java.io.File; import java.util.ArrayList; import java.util.List; impor ...

  5. lucene搜索方式(query类型)

    Lucene有多种搜索方式,可以根据需要选择不同的方式. 1.词条搜索(单个关键字查找) 主要对象是TermQuery 调用方式如下: Term term=new Term(字段名,搜索关键字);Qu ...

  6. lucene3.6笔记添加搜索功能

    lucene为程序添加搜索功能,此功能基于已创建好的文档的索引之上.这里我已经为一些文档建立了索引,并保存到硬盘上.下面开始针对这些索引,添加搜索功能. 1.简单的TermQuery搜索 Java代码 ...

  7. Lucene核心--构建Lucene搜索(上篇,理论篇)

    2.1构建Lucene搜索 2.1.1 Lucene内容模型 一个文档(document)就是Lucene建立索引和搜索的原子单元,它由一个或者多个字段(field)组成,字段才是Lucene的真实内 ...

  8. Android搜索功能的案例,本地保存搜索历史记录......

    开发的APP有一个搜索功能,并且需要显示搜索的历史记录,我闲暇之余帮她开发了这个功能,现把该页面抽取成一个demo分享给大家. 实现效果如图所示:  本案例实现起来很简单,所以可以直接拿来嵌入项目中使 ...

  9. Yii 1开发日记 -- 搜索功能及Checkbox的实现

    用yii 1实现后台的搜索功能,效果如下图: 1.模型中: public function search() { $criteria = new CDbCriteria; //独立高级搜索 if(is ...

随机推荐

  1. 机器指令翻译成 JavaScript —— No.2 跳转处理

    上一篇,我们发现大多数 6502 指令都可以直接 1:1 翻译成 JS 代码,但除了「跳转指令」. 跳转指令,分无条件跳转.条件跳转.从另一个角度,也可分: 静态跳转:目标地址已知 动态跳转:目标地址 ...

  2. 神奇的css!竟然可以这样玩转表格

    这是在对一个博客模板进行移动端适配时遇到的一个场景.html结构如下: 要解决的问题是如何在不修改任何html代码的情况下,仅仅通过css实现下面的效果: 1)改变它们的显示顺序,.MainCell显 ...

  3. JSP自定义tag

    前端需要调用后端的配置,想起velocity-tools.然而jsp的话,目前只能想到tag和EL表达式了. Tag相当好写,jsp2.0提供了简化写法: 编写一个java类: public clas ...

  4. 如何查看前端部署的tracker代码

    1.www.gov.cn 2.F12>Source>左侧选择static.gridsumdissector.com/js 3.点击代码下方区域的中括号,展开代码preety print{}

  5. kubernetes 内网节点部署笔记(一)

    在Centos7上部署kubernetes时,碰到很多坑,特别在摸拟在内网部署时,有来自GFW的障碍,有来自Firewalld的阻塞,反正是各种不服,终于慢慢理顺了思路,自己记录一下,防止遗忘. 环境 ...

  6. asp.net mvc 之旅—— 第一站 从简单的razor入手

    记得2011年mvc3刚出来的时候,我们就有幸将 mvc3 用在我们团购项目上,当时老大让我们用一个星期时间来熟悉mvc,幸好园子里面的老朋友DR 正在写mvc3系列,也恭喜这个系列文章被整理成专题供 ...

  7. python3登录极路由并读取宽带帐号帐号密码.py

    python3登录极路由并读取宽带帐号帐号密码,fiddler抓包分析过程略... 步骤:1.登录路由,提取stok. 2.用stok拼成url,post请求 3.解析json数据 代码: " ...

  8. java之final关键字

    final关键字(可以读不可以写.只读) 1.final的变量的值不能够被改变 ①.final的成员变量 ②.final的局部变量(形参) //意思是“实参”一旦传进我的方法里面,就不允许改变 2.f ...

  9. Android JNI开发生成.h头文件问题

    在JNI开发中,首先要将建立的anroid类编译成.h文件,编译用到命令javah,由于第一次用,以前对java的编译过程也不怎么了解,所以走了好多弯路,网络没有对这一步的详细介绍,这里讲一下: 通过 ...

  10. 【转载】Jmeter获取响应结果中参数出现的次数

    在测试中,有时候会遇到要统计响应结果中某个参数出现了多少次,如果量级很大,一个一个数不太现实,下面讲一下实现自动打印出该参数出现的次数的方法. 例如我的响应信息为:{"ip":&q ...