lucene&solr-day1

 

 

  全文检索课程java

Lucene&Solr1git

  

 

 

1.   计划

第一天:Lucene的基础知识github

一、案例分析:什么是全文检索,如何实现全文检索web

二、Lucene实现全文检索的流程算法

a)       建立索引spring

b)       查询索引sql

三、配置开发环境数据库

四、建立索引库apache

五、查询索引库windows

六、分析器的分析过程

a)       测试分析器的分词效果

b)       第三方中文分析器

七、索引库的维护

a)       添加文档

b)       删除文档

c)        修改文档

八、Lucene的高级查询Lucene的查询

a)       使用Query的子类查询

  1. MatchAllDocsQuery
  2. TermQuery
  3. NumericRangeQuery
  4. BooleanQuery

b)       使用QueryParser

  1. QueryParser
  2. MulitFieldQueryParser

 

 

2.   案例

实现一个文件的搜索功能,经过关键字搜索文件,凡是文件名或文件内容包括关键字的文件都须要找出来。还能够根据中文词语进行查询,而且须要支持多个条件查询。

本案例中的原始内容就是磁盘上的文件,以下图:

 

 

 

 

3.   需求分析

3.1. 数据库搜索

数据库中的搜索很容易实现,一般都是使用sql语句进行查询,并且能很快的获得查询结果。

为何数据库搜索很容易?

由于数据库中的数据存储是有规律的,有行有列并且数据格式、数据长度都是固定的。

 

3.2. 数据分类

咱们生活中的数据整体分为两种:结构化数据和非结构化数据。

结构化数据:指具备固定格式或有限长度的数据,如数据库,元数据等。

非结构化数据:指不定长或无固定格式的数据,如邮件,word文档等磁盘上的文件

 

3.3. 非结构化数据查询方法

(1)顺序扫描法(Serial Scanning)

所谓顺序扫描,好比要找内容包含某一个字符串的文件,就是一个文档一个文档的看,对于每个文档,从头看到尾,若是此文档包含此字符串,则此文档为咱们要找的文件,接着看下一个文件,直到扫描完全部的文件。如利用windows的搜索也能够搜索文件内容,只是至关的慢。

(2)全文检索(Full-text Search)

将非结构化数据中的一部分信息提取出来,从新组织,使其变得有必定结构,而后对此有必定结构的数据进行搜索,从而达到搜索相对较快的目的。这部分从非结构化数据中提取出的而后从新组织的信息,咱们称之索引

例如:字典。字典的拼音表和部首检字表就至关于字典的索引,对每个字的解释是非结构化的,若是字典没有音节表和部首检字表,在茫茫辞海中找一个字只能顺序扫描。然而字的某些信息能够提取出来进行结构化处理,好比读音,就比较结构化,分声母和韵母,分别只有几种能够一一列举,因而将读音拿出来按必定的顺序排列,每一项读音都指向此字的详细解释的页数。咱们搜索时按结构化的拼音搜到读音,而后按其指向的页数,即可找到咱们的非结构化数据——也即对字的解释。

这种先创建索引,再对索引进行搜索的过程就叫全文检索(Full-text Search)

虽然建立索引的过程也是很是耗时的,可是索引一旦建立就能够屡次使用,全文检索主要处理的是查询,因此耗时间建立索引是值得的。

3.4. 如何实现全文检索

可使用Lucene实现全文检索。Lucene是apache下的一个开放源代码的全文检索引擎工具包。提供了完整的查询引擎和索引引擎,部分文本分析引擎。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能。

 

3.5. 全文检索的应用场景

对于数据量大、数据结构不固定的数据可采用全文检索方式搜索,好比百度、Google等搜索引擎、论坛站内搜索、电商网站站内搜索等。

 

4.   Lucene实现全文检索的流程

4.1. 索引和搜索流程图

 

 

 

一、绿色表示索引过程,对要搜索的原始内容进行索引构建一个索引库,索引过程包括:

肯定原始内容即要搜索的内容à采集文档à建立文档à分析文档à索引文档

        

二、红色表示搜索过程,从索引库中搜索内容,搜索过程包括:

用户经过搜索界面à建立查询à执行搜索,从索引库搜索à渲染搜索结果

 

4.2. 建立索引

对文档索引的过程,将用户要搜索的文档内容进行索引,索引存储在索引库(index)中。

这里咱们要搜索的文档是磁盘上的文本文件,根据案例描述:凡是文件名或文件内容包括关键字的文件都要找出来,这里要对文件名和文件内容建立索引。

 

4.2.1.    得到原始文档

原始文档是指要索引和搜索的内容。原始内容包括互联网上的网页、数据库中的数据、磁盘上的文件等。

本案例中的原始内容就是磁盘上的文件,以下图:

 

 

 

 

从互联网上、数据库、文件系统中等获取须要搜索的原始信息,这个过程就是信息采集,信息采集的目的是为了对原始内容进行索引。

在Internet上采集信息的软件一般称为爬虫或蜘蛛,也称为网络机器人,爬虫访问互联网上的每个网页,将获取到的网页内容存储起来。

         Lucene不提供信息采集的类库,须要本身编写一个爬虫程序实现信息采集,也能够经过一些开源软件实现信息采集,以下:

         Nutch(http://lucene.apache.org/nutch), Nutch是apache的一个子项目,包括大规模爬虫工具,可以抓取和分辨web网站数据。

         jsoup(http://jsoup.org/ ),jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套很是省力的API,可经过DOM,CSS以及相似于jQuery的操做方法来取出和操做数据。

         heritrix(http://sourceforge.net/projects/archive-crawler/files/),Heritrix 是一个由 java 开发的、开源的网络爬虫,用户可使用它来从网上抓取想要的资源。其最出色之处在于它良好的可扩展性,方便用户实现本身的抓取逻辑。

本案例咱们要获取磁盘上文件的内容,能够经过文件流来读取文本文件的内容,对于pdf、doc、xls等文件可经过第三方提供的解析工具读取文件内容,好比Apache POI读取doc和xls的文件内容。

 

4.2.2.    建立文档对象

获取原始内容的目的是为了索引,在索引前须要将原始内容建立成文档(Document),文档中包括一个一个的域(Field),域中存储内容。

这里咱们能够将磁盘上的一个文件当成一个document,Document中包括一些Field(file_name文件名称、file_path文件路径、file_size文件大小、file_content文件内容),以下图:

 

 

 

 

注意:每一个Document能够有多个Field,不一样的Document能够有不一样的Field,同一个Document能够有相同的Field(域名和域值都相同)

 

每一个文档都有一个惟一的编号,就是文档id。

 

4.2.3.    分析文档

将原始内容建立为包含域(Field)的文档(document),须要再对域中的内容进行分析,分析的过程是通过对原始文档提取单词、将字母转为小写、去除标点符号、去除停用词等过程生成最终的语汇单元,能够将语汇单元理解为一个一个的单词。

 

好比下边的文档通过分析以下:

原文档内容:

Lucene is a Java full-text search engine.  Lucene is not a complete

application, but rather a code library and API that can easily be used

to add search capabilities to applications.

 

分析后获得的语汇单元:

lucene、java、full、search、engine。。。。

 

每一个单词叫作一个Term,不一样的域中拆分出来的相同的单词是不一样的term。term中包含两部分一部分是文档的域名,另外一部分是单词的内容。

例如:文件名中包含apache和文件内容中包含的apache是不一样的term。

4.2.4.    建立索引

对全部文档分析得出的语汇单元进行索引,索引的目的是为了搜索,最终要实现只搜索被索引的语汇单元从而找到Document(文档)。

 
   

 

 

 

注意:建立索引是对语汇单元索引,经过词语找文档,这种索引的结构叫倒排索引结构

传统方法是根据文件找到该文件的内容,在文件内容中匹配搜索关键字,这种方法是顺序扫描方法,数据量大、搜索慢。

倒排索引结构是根据内容(词语)找文档,以下图:

 

 

 

倒排索引结构也叫反向索引结构,包括索引和文档两部分,索引即词汇表,它的规模较小,而文档集合较大。

 

4.3. 查询索引

查询索引也是搜索的过程。搜索就是用户输入关键字,从索引(index)中进行搜索的过程。根据关键字搜索索引,根据索引找到对应的文档,从而找到要搜索的内容(这里指磁盘上的文件)。

 

4.3.1.    用户查询接口

全文检索系统提供用户搜索的界面供用户提交搜索的关键字,搜索完成展现搜索结果。

 

好比:

 

 

 

Lucene不提供制做用户搜索界面的功能,须要根据本身的需求开发搜索界面。

4.3.2.    建立查询

用户输入查询关键字执行搜索以前须要先构建一个查询对象,查询对象中能够指定查询要搜索的Field文档域、查询关键字等,查询对象会生成具体的查询语法,

例如:

语法 “fileName:lucene”表示要搜索Field域的内容为“lucene”的文档

 

4.3.3.    执行查询

搜索索引过程:

根据查询语法在倒排索引词典表中分别找出对应搜索词的索引,从而找到索引所连接的文档链表。

好比搜索语法为“fileName:lucene”表示搜索出fileName域中包含Lucene的文档。

搜索过程就是在索引上查找域为fileName,而且关键字为Lucene的term,并根据term找到文档id列表。

 

 

4.3.4.    渲染结果

 

以一个友好的界面将查询结果展现给用户,用户根据搜索结果找本身想要的信息,为了帮助用户很快找到本身的结果,提供了不少展现的效果,好比搜索结果中将关键字高亮显示,百度提供的快照等。

 

 

 

 

5.   配置开发环境

5.1. Lucene下载

Lucene是开发全文检索功能的工具包,从官方网站下载Lucene4.10.3,并解压。

官方网站:http://lucene.apache.org/

版本:lucene4.10.3

Jdk要求:1.7以上

IDE:Eclipse

 

5.2. 使用的jar包

 

 

Lucene包:

lucene-core-4.10.3.jar

lucene-analyzers-common-4.10.3.jar

lucene-queryparser-4.10.3.jar

 

其它:

commons-io-2.4.jar

junit-4.9.jar

 

6.   功能一:建立索引库

使用indexwriter对象建立索引

6.1. 实现步骤

第一步:建立一个java工程,并导入jar包。

第二步:建立一个indexwriter对象。

1)指定索引库的存放位置Directory对象

2)指定一个分析器,对文档内容进行分析。

第二步:建立document对象。

第三步:建立field对象,将field添加到document对象中。

第四步:使用indexwriter对象将document对象写入索引库,此过程进行索引建立。并将索引和document对象写入索引库。

第五步:关闭IndexWriter对象。

6.2. Field域的属性

是否分析:是否对域的内容进行分词处理。前提是咱们要对域的内容进行查询。

是否索引:将Field分析后的词或整个Field值进行索引,只有索引方可搜索到。

好比:商品名称、商品简介分析后进行索引,订单号、身份证号不用分析但也要索引,这些未来都要做为查询条件。

是否存储:将Field值存储在文档中,存储在文档中的Field才能够从Document中获取

好比:商品名称、订单号,凡是未来要从Document中获取的Field都要存储。

 

是否存储的标准:是否要将内容展现给用户

 

Field类

数据类型

Analyzed

是否分析

Indexed

是否索引

Stored

是否存储

说明

StringField(FieldName, FieldValue,Store.YES))

字符串

N

Y

Y或N

这个Field用来构建一个字符串Field,可是不会进行分析,会将整个串存储在索引中,好比(订单号,姓名等)

是否存储在文档中用Store.YES或Store.NO决定

LongField(FieldName, FieldValue,Store.YES)

Long型

Y

Y

Y或N

这个Field用来构建一个Long数字型Field,进行分析和索引,好比(价格)

是否存储在文档中用Store.YES或Store.NO决定

StoredField(FieldName, FieldValue)

重载方法,支持多种类型

N

N

Y

这个Field用来构建不一样类型Field

不分析,不索引,但要Field存储在文档中

TextField(FieldName, FieldValue, Store.NO)

TextField(FieldName, reader)

 

字符串

Y

Y

Y或N

若是是一个Reader, lucene猜想内容比较多,会采用Unstored的策略.

 

6.3. 代码实现

//建立索引

     @Test

     public void createIndex() throws Exception {

         

          //指定索引库存放的路径

          //D:\temp\0108\index

          Directory directory = FSDirectory.open(new File("D:\\temp\\0108\\index"));

          //索引库还能够存放到内存中

          //Directory directory = new RAMDirectory();

          //建立一个标准分析器

          Analyzer analyzer = new StandardAnalyzer();

          //建立indexwriterCofig对象

          //第一个参数: Lucene的版本信息,能够选择对应的lucene版本也可使用LATEST

          //第二根参数:分析器对象

          IndexWriterConfig config = new IndexWriterConfig(Version.LATEST, analyzer);

          //建立indexwriter对象

          IndexWriter indexWriter = new IndexWriter(directory, config);

          //原始文档的路径D:\传智播客\01.课程\04.lucene\01.参考资料\searchsource

          File dir = new File("D:\\传智播客\\01.课程\\04.lucene\\01.参考资料\\searchsource");

          for (File f : dir.listFiles()) {

               //文件名

               String fileName = f.getName();

               //文件内容

               String fileContent = FileUtils.readFileToString(f);

               //文件路径

               String filePath = f.getPath();

               //文件的大小

               long fileSize  = FileUtils.sizeOf(f);

               //建立文件名域

               //第一个参数:域的名称

               //第二个参数:域的内容

               //第三个参数:是否存储

               Field fileNameField = new TextField("filename", fileName, Store.YES);

               //文件内容域

               Field fileContentField = new TextField("content", fileContent, Store.YES);

               //文件路径域(不分析、不索引、只存储)

               Field filePathField = new StoredField("path", filePath);

               //文件大小域

               Field fileSizeField = new LongField("size", fileSize, Store.YES);

              

               //建立document对象

               Document document = new Document();

               document.add(fileNameField);

               document.add(fileContentField);

               document.add(filePathField);

               document.add(fileSizeField);

               //建立索引,并写入索引库

               indexWriter.addDocument(document);

          }

          //关闭indexwriter

          indexWriter.close();

     }

 

6.4. 使用Luke工具查看索引文件

 

 

 

7.   功能二:查询索引

7.1. 实现步骤

第一步:建立一个Directory对象,也就是索引库存放的位置。

第二步:建立一个indexReader对象,须要指定Directory对象。

第三步:建立一个indexsearcher对象,须要指定IndexReader对象

第四步:建立一个TermQuery对象,指定查询的域和查询的关键词。

第五步:执行查询。

第六步:返回查询结果。遍历查询结果并输出。

第七步:关闭IndexReader对象

7.2. IndexSearcher搜索方法

 

方法

说明

indexSearcher.search(query, n)

根据Query搜索,返回评分最高的n条记录

indexSearcher.search(query, filter, n)

根据Query搜索,添加过滤策略,返回评分最高的n条记录

indexSearcher.search(query, n, sort)

根据Query搜索,添加排序策略,返回评分最高的n条记录

indexSearcher.search(booleanQuery, filter, n, sort)

根据Query搜索,添加过滤策略,添加排序策略,返回评分最高的n条记录

 

7.3. 代码实现

//查询索引库

     @Test

     public void searchIndex() throws Exception {

          //指定索引库存放的路径

          //D:\temp\0108\index

          Directory directory = FSDirectory.open(new File("D:\\temp\\0108\\index"));

          //建立indexReader对象

          IndexReader indexReader = DirectoryReader.open(directory);

          //建立indexsearcher对象

          IndexSearcher indexSearcher = new IndexSearcher(indexReader);

          //建立查询

          Query query = new TermQuery(new Term("filename", "apache"));

          //执行查询

          //第一个参数是查询对象,第二个参数是查询结果返回的最大值

          TopDocs topDocs = indexSearcher.search(query, 10);

          //查询结果的总条数

          System.out.println("查询结果的总条数:"+ topDocs.totalHits);

          //遍历查询结果

          //topDocs.scoreDocs存储了document对象的id

          for (ScoreDoc scoreDoc : topDocs.scoreDocs) {

               //scoreDoc.doc属性就是document对象的id

               //根据document的id找到document对象

               Document document = indexSearcher.doc(scoreDoc.doc);

               System.out.println(document.get("filename"));

               //System.out.println(document.get("content"));

               System.out.println(document.get("path"));

               System.out.println(document.get("size"));

          }

          //关闭indexreader对象

          indexReader.close();

     }

7.4. TopDocs

 

Lucene搜索结果可经过TopDocs遍历,TopDocs类提供了少许的属性,以下:

 

方法或属性

说明

totalHits

匹配搜索条件的总记录数

scoreDocs

顶部匹配记录

 

注意:

Search方法须要指定匹配记录数量n:indexSearcher.search(query, n)

TopDocs.totalHits:是匹配索引库中全部记录的数量

TopDocs.scoreDocs:匹配相关度高的前边记录数组,scoreDocs的长度小于等于search方法指定的参数n

 

8.   功能三:支持中文分词

8.1. 分析器(Analyzer)的执行过程

以下图是语汇单元的生成过程:

 

 

 

 

从一个Reader字符流开始,建立一个基于Reader的Tokenizer分词器,通过三个TokenFilter生成语汇单元Tokens。

要看分析器的分析效果,只须要看Tokenstream中的内容就能够了。每一个分析器都有一个方法tokenStream,返回一个tokenStream对象。

 

8.2. 分析器的分词效果

//查看标准分析器的分词效果

     public void testTokenStream() throws Exception {

          //建立一个标准分析器对象

          Analyzer analyzer = new StandardAnalyzer();

          //得到tokenStream对象

          //第一个参数:域名,能够随便给一个

          //第二个参数:要分析的文本内容

          TokenStream tokenStream = analyzer.tokenStream("test", "The Spring Framework provides a comprehensive programming and configuration model.");

          //添加一个引用,能够得到每一个关键词

          CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);

          //添加一个偏移量的引用,记录了关键词的开始位置以及结束位置

          OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);

          //将指针调整到列表的头部

          tokenStream.reset();

          //遍历关键词列表,经过incrementToken方法判断列表是否结束

          while(tokenStream.incrementToken()) {

               //关键词的起始位置

               System.out.println("start->" + offsetAttribute.startOffset());

               //取关键词

               System.out.println(charTermAttribute);

               //结束位置

               System.out.println("end->" + offsetAttribute.endOffset());

          }

          tokenStream.close();

     }

 

8.3. 中文分析器

8.3.1.    Lucene自带中文分词器

l  StandardAnalyzer:

单字分词:就是按照中文一个字一个字地进行分词。如:“我爱中国”,
效果:“我”、“爱”、“中”、“国”。

l  CJKAnalyzer

二分法分词:按两个字进行切分。如:“我是中国人”,效果:“我是”、“是中”、“中国”“国人”。

 

上边两个分词器没法知足需求。

l  SmartChineseAnalyzer

对中文支持较好,但扩展性差,扩展词库,禁用词库和同义词库等很差处理

8.3.2.    第三方中文分析器

  • paoding: 庖丁解牛最新版在 https://code.google.com/p/paoding/ 中最多支持Lucene 3.0,且最新提交的代码在 2008-06-03,在svn中最新也是2010年提交,已通过时,不予考虑。
  • mmseg4j:最新版已从 https://code.google.com/p/mmseg4j/ 移至 https://github.com/chenlb/mmseg4j-solr,支持Lucene 4.10,且在github中最新提交代码是2014年6月,从09年~14年一共有:18个版本,也就是一年几乎有3个大小版本,有较大的活跃度,用了mmseg算法。
  • IK-analyzer: 最新版在https://code.google.com/p/ik-analyzer/上,支持Lucene 4.10从2006年12月推出1.0版开始, IKAnalyzer已经推出了4个大版本。最初,它是以开源项目Luence为应用主体的,结合词典分词和文法分析算法的中文分词组件。从3.0版本开 始,IK发展为面向Java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现。在2012版本中,IK实现了简单的分词 歧义排除算法,标志着IK分词器从单纯的词典分词向模拟语义分词衍化。 可是也就是2012年12月后没有在更新。
  • ansj_seg:最新版本在 https://github.com/NLPchina/ansj_seg tags仅有1.1版本,从2012年到2014年更新了大小6次,可是做者本人在2014年10月10日说明:“可能我之后没有精力来维护ansj_seg了”,如今由”nlp_china”管理。2014年11月有更新。并未说明是否支持Lucene,是一个由CRF(条件随机场)算法所作的分词算法。
  • imdict-chinese-analyzer:最新版在 https://code.google.com/p/imdict-chinese-analyzer/ , 最新更新也在2009年5月,下载源码,不支持Lucene 4.10 。是利用HMM(隐马尔科夫链)算法。
  • Jcseg:最新版本在git.oschina.net/lionsoul/jcseg,支持Lucene 4.10,做者有较高的活跃度。利用mmseg算法。

8.3.3.    IKAnalyzer

 

 

使用方法:

第一步:把jar包添加到工程中

第二步:把配置文件和扩展词典和停用词词典添加到classpath下

 

注意:mydict.dic和ext_stopword.dic文件的格式为UTF-8,注意是无BOM 的UTF-8 编码。

 mydict.dic内容是本身定义扩展的词汇来分词:

高富帅
白富美
二维表


 ext_stopword.dic内容是本身禁止词汇来分词:








a
an
and
are
as
at
be
but
by
for
if
in
into
is
it
no
not
of
on
or
such
that
the
their
then
there
these
they
this
to
was
will
with

使用EditPlus.exe保存为无BOM 的UTF-8 编码格式,以下图:

 

 

8.4. Analyzer使用时机

8.4.1.    索引时使用Analyzer

         输入关键字进行搜索,当须要让该关键字与文档域内容所包含的词进行匹配时须要对文档域内容进行分析,须要通过Analyzer分析器处理生成语汇单元(Token)。分析器分析的对象是文档中的Field域。当Field的属性tokenized(是否分词)为true时会对Field值进行分析,以下图:

 

 

 

对于一些Field能够不用分析:

一、不做为查询条件的内容,好比文件路径

二、不是匹配内容中的词而匹配Field的总体内容,好比订单号、身份证号等。

 

 

8.4.2.    搜索时使用Analyzer

         对搜索关键字进行分析和索引分析同样,使用Analyzer对搜索关键字进行分析、分词处理,使用分析后每一个词语进行搜索。好比:搜索关键字:spring web ,通过分析器进行分词,得出:spring  web拿词去索引词典表查找 ,找到索引连接到Document,解析Document内容。

         对于匹配总体Field域的查询能够在搜索时不分析,好比根据订单号、身份证号查询等。

 

         注意:搜索使用的分析器要和索引使用的分析器一致。

 

9.   功能四:索引库的维护

9.1. 索引库的添加

9.1.1.    步骤

向索引库中添加document对象。

第一步:先建立一个indexwriter对象

第二步:建立一个document对象

第三步:把document对象写入索引库

第四步:关闭indexwriter。

 

9.1.2.    代码实现

//添加索引

     @Test

     public void addDocument() throws Exception {

          //索引库存放路径

          Directory directory = FSDirectory.open(new File("D:\\temp\\0108\\index"));

         

          IndexWriterConfig config = new IndexWriterConfig(Version.LATEST, new IKAnalyzer());

          //建立一个indexwriter对象

          IndexWriter indexWriter = new IndexWriter(directory, config);

          //建立一个Document对象

          Document document = new Document();

          //向document对象中添加域。

          //不一样的document能够有不一样的域,同一个document能够有相同的域。

          document.add(new TextField("filename", "新添加的文档", Store.YES));

          document.add(new TextField("content", "新添加的文档的内容", Store.NO));

          document.add(new TextField("content", "新添加的文档的内容第二个content", Store.YES));

          document.add(new TextField("content1", "新添加的文档的内容要能看到", Store.YES));

          //添加文档到索引库

          indexWriter.addDocument(document);

          //关闭indexwriter

          indexWriter.close();

         

     }

 

9.2. 索引库删除

9.2.1.    删除所有

//删除所有索引

     @Test

     public void deleteAllIndex() throws Exception {

          IndexWriter indexWriter = getIndexWriter();

          //删除所有索引

          indexWriter.deleteAll();

          //关闭indexwriter

          indexWriter.close();

     }

 

说明:将索引目录的索引信息所有删除,直接完全删除,没法恢复。

 

此方法慎用!!

 

9.2.2.    指定查询条件删除

//根据查询条件删除索引

     @Test

     public void deleteIndexByQuery() throws Exception {

          IndexWriter indexWriter = getIndexWriter();

          //建立一个查询条件

          Query query = new TermQuery(new Term("filename", "apache"));

          //根据查询条件删除

          indexWriter.deleteDocuments(query);

          //关闭indexwriter

          indexWriter.close();

     }

 

9.3. 索引库的修改

原理就是先删除后添加。

//修改索引库

     @Test

     public void updateIndex() throws Exception {

          IndexWriter indexWriter = getIndexWriter();

          //建立一个Document对象

          Document document = new Document();

          //向document对象中添加域。

          //不一样的document能够有不一样的域,同一个document能够有相同的域。

          document.add(new TextField("filename", "要更新的文档", Store.YES));

          document.add(new TextField("content", "2013年11月18日 - Lucene 简介 Lucene 是一个基于 Java 的全文信息检索工具包,它不是一个完整的搜索应用程序,而是为你的应用程序提供索引和搜索功能。", Store.YES));

          indexWriter.updateDocument(new Term("content", "java"), document);

          //关闭indexWriter

          indexWriter.close();

     }

 

10.        Lucene索引库查询(重点)

         对要搜索的信息建立Query查询对象,Lucene会根据Query查询对象生成最终的查询语法,相似关系数据库Sql语法同样Lucene也有本身的查询语法,好比:“name:lucene”表示查询Field的name为“lucene”的文档信息。

         可经过两种方法建立查询对象:

         1)使用Lucene提供Query子类

         Query是一个抽象类,lucene提供了不少查询对象,好比TermQuery项精确查询,NumericRangeQuery数字范围查询等。

         以下代码:

          Query query = new TermQuery(new Term("name", "lucene"));

 

         2)使用QueryParse解析查询表达式

         QueryParse会将用户输入的查询表达式解析成Query对象实例。

         以下代码:

           QueryParser queryParser = new QueryParser("name", new IKAnalyzer());

           Query query = queryParser.parse("name:lucene");

 

 

10.1.    使用query的子类查询

10.1.1.          MatchAllDocsQuery

使用MatchAllDocsQuery查询索引目录中的全部文档

@Test

     public void testMatchAllDocsQuery() throws Exception {

          IndexSearcher indexSearcher = getIndexSearcher();

          //建立查询条件

          Query query = new MatchAllDocsQuery();

          //执行查询

          printResult(query, indexSearcher);

     }

 

10.1.2.          TermQuery

TermQuery,经过项查询,TermQuery不使用分析器因此建议匹配不分词的Field域查询,好比订单号、分类ID号等。

指定要查询的域和要查询的关键词。

//使用Termquery查询

     @Test

     public void testTermQuery() throws Exception {

          IndexSearcher indexSearcher = getIndexSearcher();

          //建立查询对象

          Query query = new TermQuery(new Term("content", "lucene"));

          //执行查询

          TopDocs topDocs = indexSearcher.search(query, 10);

          //共查询到的document个数

          System.out.println("查询结果总数量:" + topDocs.totalHits);

          //遍历查询结果

          for (ScoreDoc scoreDoc : topDocs.scoreDocs) {

               Document document = indexSearcher.doc(scoreDoc.doc);

               System.out.println(document.get("filename"));

               //System.out.println(document.get("content"));

               System.out.println(document.get("path"));

               System.out.println(document.get("size"));

          }

          //关闭indexreader

          indexSearcher.getIndexReader().close();

     }

 

10.1.3.          NumericRangeQuery

能够根据数值范围查询。

//数值范围查询

     @Test

     public void testNumericRangeQuery() throws Exception {

          IndexSearcher indexSearcher = getIndexSearcher();

          //建立查询

          //参数:

          //1.域名

          //2.最小值

          //3.最大值

          //4.是否包含最小值

          //5.是否包含最大值

          Query query = NumericRangeQuery.newLongRange("size", 1l, 1000l, true, true);

          //执行查询

          printResult(query, indexSearcher);

     }

 

10.1.4.          BooleanQuery

能够组合查询条件。

//组合条件查询

     @Test

     public void testBooleanQuery() throws Exception {

          IndexSearcher indexSearcher = getIndexSearcher();

          //建立一个布尔查询对象

          BooleanQuery query = new BooleanQuery();

          //建立第一个查询条件

          Query query1 = new TermQuery(new Term("filename", "apache"));

          Query query2 = new TermQuery(new Term("content", "apache"));

          //组合查询条件

          query.add(query1, Occur.MUST);

          query.add(query2, Occur.MUST);

          //执行查询

          printResult(query, indexSearcher);

     }

 

Occur.MUST:必须知足此条件,至关于and

Occur.SHOULD:应该知足,可是不知足也能够,至关于or

Occur.MUST_NOT:必须不知足。至关于not

 

 

10.2.    使用queryparser查询

经过QueryParser也能够建立Query,QueryParser提供一个Parse方法,此方法能够直接根据查询语法来查询。Query对象执行的查询语法可经过System.out.println(query);查询。

须要使用到分析器。建议建立索引时使用的分析器和查询索引时使用的分析器要一致。

 

10.2.1.          QueryParser

须要加入queryParser依赖的jar包。

 

 

1.1.1.1           程序实现

@Test

     public void testQueryParser() throws Exception {

          IndexSearcher indexSearcher = getIndexSearcher();

          //建立queryparser对象

          //第一个参数默认搜索的域

          //第二个参数就是分析器对象

          QueryParser queryParser = new QueryParser("content", new IKAnalyzer());

          Query query = queryParser.parse("Lucene是java开发的");

          //执行查询

          printResult(query, indexSearcher);

     }

 

1.1.1.2           查询语法

一、基础的查询语法,关键词查询:

域名+“:”+搜索的关键字

例如:content:java

二、范围查询

域名+“:”+[最小值 TO 最大值]

例如:size:[1 TO 1000]

范围查询在lucene中支持数值类型,不支持字符串类型。在solr中支持字符串类型。

三、组合条件查询

1)+条件1 +条件2:两个条件之间是而且的关系and

例如:+filename:apache +content:apache

2)+条件1 条件2:必须知足第一个条件,应该知足第二个条件

例如:+filename:apache content:apache

3)条件1 条件2:两个条件知足其一便可。

例如:filename:apache content:apache

4)-条件1 条件2:必须不知足条件1,要知足条件2

例如:-filename:apache content:apache

Occur.MUST 查询条件必须知足,至关于and

+(加号)

Occur.SHOULD 查询条件可选,至关于or

 

空(不用符号)

Occur.MUST_NOT 查询条件不能知足,至关于not非

-(减号)

 

第二种写法:

条件1 AND 条件2

条件1 OR 条件2

条件1 NOT 条件2

 

10.2.2.          MultiFieldQueryParser

能够指定多个默认搜索域

@Test

     public void testMultiFiledQueryParser() throws Exception {

          IndexSearcher indexSearcher = getIndexSearcher();

          //能够指定默认搜索的域是多个

          String[] fields = {"filename", "content"};

          //建立一个MulitFiledQueryParser对象

          MultiFieldQueryParser queryParser = new MultiFieldQueryParser(fields, new IKAnalyzer());

          Query query = queryParser.parse("java AND apache");

          System.out.println(query);

          //执行查询

          printResult(query, indexSearcher);

         

     }

 

 

 

txt

本站公众号
   欢迎关注本站公众号,获取更多信息