Lucene的常用操作详解,crud

全文检索技术——Lucene

2 数据的分类
日常生活中常见的数据分类:分成两类
1、结构化数据:数据格式固定、数据类型固定、有限长度。(例如:数据库中的数据)
2、非结构化数据:数据格式不固定,txt、excel、word、pdf、数据类型不固定、长度不固定。(例如:磁盘中的文件)

2.1 结构化数据的查询
查询方便,可以使用sql语句查询数据库中的数据。

2.2 非结构化数据的查询
查询方法:
1、目测
2、顺序扫描:使用java程序把文件读取到内存中,然后匹配字符串。
3、顺序扫描适应于数据量不是很大的情况下。如果数据非常大情况下可以把非结构化数据结构化。可以把文件中的内容根据空格进行分词,在得到的字符串列表基础上创建索引,可以快速找到关键词,可以根据关键词找到对应的文档。这个过程就叫做全文检索的过程

3 什么是全文检索
全文检索是一种将文件中所有文本与检索项匹配的文字资料检索方法。全文检索首先将要查询的目标文档中的词提取出来,组成索引,通过查询索引达到搜索目标文档的目的。
这种先建立索引,再对索引进行搜索的过程就叫全文检索(Full-text Search)。

4 全文检索的应用领域
1、全文检索可以实现搜索引擎。例如百度、谷歌等。
2、站内搜素。论坛搜索、微博搜索。
3、电商搜索。例如京东、淘宝

只要有查询的地方就可以使用全文检索。

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

6 Lucene的下载及安装
6.1 下载
Lucene的常用操作详解,crud_第1张图片
我们使用的版本:
4.10.3
Lucene的常用操作详解,crud_第2张图片

6.2 安装
添加到工程中即可。

6.3 Lucene的包结构
Lucene的常用操作详解,crud_第3张图片

7 Lucene如何实现全文检索
7.1 案例描述
我们以一个案例来研究全文检索系统架构:实现一个文件的搜索功能,通过关键字搜索文件,凡是文件名或文件内容包括关键字的文件都需要找出来。
Lucene的常用操作详解,crud_第4张图片

7.2 索引和搜索流程图
Lucene的常用操作详解,crud_第5张图片
7.2.1 创建索引
7.2.1.1 获得文档
原始文档:等待搜索的文档就是原始文档。本例中txt文件就是原始文档。

搜索引擎的原始文档:整个互联网上的网页内容。
电商搜索:所有的商品信息就是原始文档。
如何获得原始文档:
本例:可以使用io流读取文本文档的内容。
搜索引擎:可以使用网络爬虫抓取网站的网页。
开源的网络爬虫:Nutch也是Apache的开源项目。Heritrix开源的爬虫项目。
Nutch(http://lucene.apache.org/nutch), Nutch是apache的一个子项目,包括大规模爬虫工具,能够抓取和分辨web网站数据。

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

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

电商网站:
可以使用sql语句查询到商品信息放到索引库中。
Solr(http://lucene.apache.org/solr) ,solr是apache的一个子项目,支持从关系数据库、xml文档中提取原始数据。

7.2.1.2 创建文档对象
创建一个Document对象,为每个文件对应的创建一个文档对象。文有多个属性,有文件名、文件内容、文件大小、文件路径。

Lucene的常用操作详解,crud_第6张图片

一个文档中有多个field,叫做域。每个域中存储不同的属性。文档中的域不固定。每个域都有一个名字。不同的文档中可以有不同的域。同一个文档中也可以有同名的域。

7.2.1.3 分析文档
根据需要对域的内容进行分析,分析就是分词的过程。如果不查询就可以不分析。
分析过程:
1、根据空格进行分词
2、去除标点符号。
3、去除停用词(拆分处理的没有意义的词叫做停用词)
4、进行大小写转换,全部转换成小写。
最终得到一个语汇单元流。就是一个关键词列表。

7.2.1.4 创建索引
基于上一步得到的词汇列表创建一个索引。还要把关键词及文档的对应关系保存下来。保存到索引库(磁盘上的文档)中

Lucene的常用操作详解,crud_第7张图片

对所有文档分析得出的语汇单元进行索引,索引的目的是为了搜索,最终要实现只搜索被索引的语汇单元从而找到Document(文档)。
注意:创建索引是对语汇单元索引,通过词语找文档,这种索引的结构叫倒排索引结构。
传统方法是根据文件找到该文件的内容,在文件内容中匹配搜索关键字,这种方法是顺序扫描方法,数据量大、搜索慢。
倒排索引结构是根据内容(词语)找文档,如下图:
Lucene的常用操作详解,crud_第8张图片

索引库可以一次创建多次查询。查询速度就很快。

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

7.2.2 查询索引
7.2.2.1 用户查询接口
用户输入查询条件的地方。
Lucene的常用操作详解,crud_第9张图片
Lucene并不提供用户接口,需要我们自己实现。

7.2.2.2 创建查询
根据用户输入的查询条件创建一个查询对象。查询对象分为两部分。
1、要搜索的域
2、要搜索的关键字。要搜素什么。

7.2.2.3 执行查询
根据查询条件到索引库中进行搜素。返回搜索结果。返回文档的id。

7.2.2.4 渲染结果
根据返回的文档id取Document对象。从Document对象中把域的内容取出来,展示给用户。
包含高亮显示、排序、分页等处理。
Lucene的常用操作详解,crud_第10张图片

8 入门程序
8.1 创建索引
8.1.1 开发环境:
要求jdk1.7以上版本。
Ide:Eclipse Indigo
Lucene:4.10.3

8.1.2 实现步骤
第一步:创建一个java工程,使用JUnit测试。
第二步:导入Lucene的jar包。
第三步:索引库的存放位置。可以是磁盘也可以是内存。
第四步:创建一个IndexWriter对象。需要索引库的存放位置,以及分析器对象。
第五步:获得原始文档。可以使用IO流读取文件的内容。
第六步:创建Document对象。
第七步:向文档中添加field。
常用的域:
域有三个属性:
1、是否分析:是否需要把文本内容中的关键词拆分处理。
2、是否索引:是否需要在域上进行搜索。
3、是否存储:是否需要展示给用户。
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的策略.

第八步:使用IndexWriter对象把Document对象写入索引库。
第九步:关闭IndexWriter。

8.1.3 代码实现
8.1.3.1 创建工程
Lucene的常用操作详解,crud_第11张图片
8.1.3.2 导入jar包
lucene-core-4.10.3.jar
lucene-analyzers-common-4.10.3.jar
commons-io-2.4.jar

8.1.3.3 代码实现
//创建索引
public void createIndex() throws Exception {
// 第一步:创建一个java工程,使用JUnit测试。
// 第二步:导入Lucene的jar包。
// 第三步:索引库的存放位置。可以是磁盘也可以是内存。
//D:\temp\0619\index
//索引库存到到内存中
//Directory directory = new RAMDirectory();
//放到磁盘上
Directory directory = FSDirectory.open(new File(“D:\temp\0619\index”));
// 第四步:创建一个IndexWriter对象。需要索引库的存放位置,以及分析器对象。
//创建一个分析器对象
Analyzer analyzer = new StandardAnalyzer();
//创建IndexWriterConfig对象
//第一个参数:Lucene匹配的版本。可以是LATEST也可以是Lucene_4_10_3
IndexWriterConfig conf = new IndexWriterConfig(Version.LATEST, analyzer);
IndexWriter indexWriter = new IndexWriter(directory, conf);
// 第五步:获得原始文档。可以使用IO流读取文件的内容。
//从D:\temp\01.课程\04.lucene\01.参考资料\searchsource目录中读取所有的txt文件
File dir = new File(“D:\temp\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);
// 第六步:创建Document对象。
Document document = new Document();
//创建域
//第一个参数:域的名称
//第二个参数:域名的内容
//第三个参数:是否存储Store.YES 存储 Store.NO 不存储
Field fileNameField = new TextField(“name”, fileName, Store.YES);
Field fileContentField = new TextField(“content”, fileContent, Store.NO);
Field filePathField = new StoredField(“path”, filePath);
Field fileSizeField = new LongField(“size”, fileSize, Store.YES);
// 第七步:向文档中添加field。
document.add(fileNameField );
document.add(fileContentField );
document.add(filePathField );
document.add(fileSizeField );
// 第八步:使用IndexWriter对象把Document对象写入索引库。
indexWriter.addDocument(document);
}
// 第九步:关闭IndexWriter。
indexWriter.close();
}

8.1.3.4 索引库
Lucene的常用操作详解,crud_第12张图片

8.2 查询索引库
8.2.1 使用Luke查看索引库
可以使用Luke工具查看索引库的结构:

Lucene的常用操作详解,crud_第13张图片
Lucene的常用操作详解,crud_第14张图片
Term:每个关键词叫做一个term。
在不同的域下,相同的字符串是不同的关键词。是不同的term。
Term中包含两部分内容:
1、域的名称
2、关键词
注意:如果关键词在索引中不存在,是搜索不到的。

8.2.2 使用java代码查询
8.2.2.1 查询步骤
第一步:创建一个IndexReader对象。需要指定索引库的位置Directory对象。
第二步:创建IndexSearcher对象,构造方法需要一个IndexReader对象。
第三步:创建一个查询对象。需要指定要查询的域以及要查询的关键字。
第四步:执行查询。返回查询结果。返回文档id的集合。
第五步:根据id取Document对象。
第六步:从Document对象中取Filed的内容。打印内容。
第七步:关闭IndexReader对象。

8.2.2.2 代码实现

//查询索引库
@Test
public void SearchIndex() throws Exception {

    // 第一步:创建一个IndexReader对象。需要指定索引库的位置Directory对象。
    Directory directory = FSDirectory.open(new File("D:\\temp\\0619\\index"));
    IndexReader indexReader = DirectoryReader.open(directory);
    // 第二步:创建IndexSearcher对象,构造方法需要一个IndexReader对象。
    IndexSearcher indexSearcher = new IndexSearcher(indexReader);
    // 第三步:创建一个查询对象。需要指定要查询的域以及要查询的关键字。
    Query query = new TermQuery(new Term("name", "apache"));
    // 第四步:执行查询。返回查询结果。返回文档id的集合。
    //第一个参数:query对象
    //第二个参数:返回结果的数量
    TopDocs topDocs = indexSearcher.search(query, 10);
    System.out.println("查询结果的总数量:" + topDocs.totalHits);
    // 第五步:根据id取Document对象。
    ScoreDoc[] scoreDocs = topDocs.scoreDocs;
    for (ScoreDoc scoreDoc : scoreDocs) {
        //文档对应的id
        int doc = scoreDoc.doc;
        //根据id取文档对象
        Document document = indexSearcher.doc(doc);
        // 第六步:从Document对象中取Filed的内容。打印内容。
        System.out.println(document.get("name"));
        System.out.println(document.get("path"));
        System.out.println(document.get("size"));

    }
    // 第七步:关闭IndexReader对象。
    indexReader.close();
}

9 分析器Analyzer
9.1 分析器的分词过程
Lucene的常用操作详解,crud_第15张图片
Lucene的常用操作详解,crud_第16张图片
如果想查看一个分析器的分词效果,可以查看TokenStream中的关键词的列表即可。Analyzer是以分析器的父类。它有一个抽象方法tokenStream可以返回一个TokenStream对象。

9.2 查看分析器的分词效果
查看标准分析器的分词效果。

实现步骤:
第一步:创建一个标准分析器对象
第二步:调用TokenStream方法获得TokenStream对象。方法中有一个参数可以指定要分析的文本内容。
第三步:设置关键词的引用。
第四步:使用while循环读取TokenStream中的关键词列表
第五步:关闭TokenStream对象。

//查看分析器的分词效果
@Test
public void testTokenStream() throws Exception {
// 第一步:创建一个标准分析器对象
Analyzer analyzer = new StandardAnalyzer();
// 第二步:调用TokenStream方法获得TokenStream对象。方法中有一个参数可以指定要分析的文本内容。
TokenStream tokenStream = analyzer.tokenStream(“”, “The Spring Framework provides a comprehensive programming and configuration model.”);
// 第三步:设置关键词的引用。
CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
// 第四步:使用while循环读取TokenStream中的关键词列表
//调用TokenStream的reset方法。
tokenStream.reset();
//如果incrementToken返回false循环结束
while(tokenStream.incrementToken()) {
//打印关键词
System.out.println(charTermAttribute.toString());
}
// 第五步:关闭TokenStream对象。
tokenStream.close();
}

标准分析器对中文的分析效果:一个汉字一个关键词。不能用。

9.3 中文分析器
1、CJKAnalyzer:中日韩统一表意文字(CJK Unified Ideographs)
两个汉字一个关键词。不能用。
2、智能中文分析器:需要把分析器需要的jar包添加到工程中。
Lucene的常用操作详解,crud_第17张图片
基本可以使用。扩展关键词不是很方便。

9.4 第三方中文分析器
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算法。
9.5 IK-Analyzer
Lucene的常用操作详解,crud_第18张图片

9.5.1 使用方法
第一步:把IKAnalyzer2012FF_u1.jar添加工程中
第二步:把配置文件、扩展词典、停用词词典放到工程的classpath下。
Lucene的常用操作详解,crud_第19张图片
注意:扩展词典、停用词词典的字符集一定是utf-8。不要使用notepad编辑扩展词典。

如果不是utf-8字符串,扩展词典无效。

9.5.2 测试分词效果
Lucene的常用操作详解,crud_第20张图片

9.6 分析器的应用场景
1、创建索引时使用分析器
2、查询索引时也需要使用分析器。先把查询的内容进行分词根据分词后的结果进行组合查询。

注意:创建索引和查询索引时使用的分析器要一致。

10 索引库的维护
包括索引库的增删改操作。

10.1 添加文档
实现步骤:
1、打开索引库。IndexWriter对象。
2、创建一个Document对象
3、向文档对象中添加域
4、把Document对象写入索引库
5、关闭IndexWriter。
//添加文档
@Test
public void addDocument() throws Exception{
//1、打开索引库。IndexWriter对象。
Directory directory = FSDirectory.open(new File(“D:\temp\0619\index”));
IndexWriterConfig config = new IndexWriterConfig(Version.LATEST, new IKAnalyzer());
IndexWriter indexWriter = new IndexWriter(directory, config);
// 2、创建一个Document对象
Document document = new Document();
// 3、向文档对象中添加域
document.add(new TextField(“name”, “新添加的文档”, Store.YES));
document.add(new TextField(“content”, “Lucene 是一个基于 Java 的全文信息检索工具包_51CTO下载中心”, Store.YES));
// 4、把Document对象写入索引库
indexWriter.addDocument(document);
// 5、关闭IndexWriter。
indexWriter.commit();
indexWriter.close();
}

10.2 删除文档
10.2.1 删除全部文档
使用IndexWriter操作索引库。

步骤:
1、创建一个IndexWriter对象
2、调用删除方法。
3、Commit。Close。
//删除文档
@Test
public void deleteAllDocument() throws Exception {
IndexWriter indexWriter = getIndexWriter();
//调用删除方法
indexWriter.deleteAll();
//更新
indexWriter.commit();
indexWriter.close();
}

慎用此方法。

10.2.2 根据查询删除
删除时指定一个查询条件,查询到多少文档就删除多少文档。
//根据查询删除文档
@Test
public void deleteDocumentByQuery() throws Exception{
IndexWriter indexWriter = getIndexWriter();
//调用删除方法
indexWriter.deleteDocuments(new TermQuery(new Term(“name”, “apache”)));
//关闭IndexWriter
indexWriter.close();
}

10.3 更新文档
更新的原理是先删除后添加。
//更新文档
@Test
public void updateDocument() throws Exception {
IndexWriter indexWriter = getIndexWriter();
//创建一新文档
Document document = new Document();
document.add(new TextField(“name”, “新更新的文档”, Store.YES));
document.add(new TextField(“content”, “构,提供了完整的查询引擎和索引引擎,部分文本分析引擎。Lucene的目的是为软件..”, Store.YES));
//更新文档
indexWriter.updateDocument(new Term(“name”, “spring”), document);
indexWriter.close();
}

11 索引库的查询
11.1 使用Query的子类
11.1.1 MatchAllDocsQuery
查询索引库中所有的文档。
//查询索引库中所有的文档
@Test
public void queryAllDocs() throws Exception {
//创建一个IndexReader对象
Directory directory = FSDirectory.open(new File(“D:\temp\0619\index”));
IndexReader indexReader = DirectoryReader.open(directory);
//创建一个IndexSearcher对象
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
//创建一个查询对象
Query query = new MatchAllDocsQuery();
//执行查询
TopDocs topDocs = indexSearcher.search(query, 10);
//查询结果的总数量
System.out.println(“查询结果总数量:” + topDocs.totalHits);
//遍历文档对象
for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
//根据文档id获得Document对象
Document document = indexSearcher.doc(scoreDoc.doc);
//取document的属性
System.out.println(document.get(“name”));
System.out.println(document.get(“content”));
System.out.println(document.get(“path”));
System.out.println(document.get(“size”));

    }

    indexReader.close();

}

11.1.2 TermQuery
根据关键词进行搜索
指定要搜索的域以及要搜索的关键词。

//使用TermQuery查询
@Test
public void searchByTerm() throws Exception {
//获得IndexSearcher对象
IndexSearcher indexSearcher = getIndexSearcher();
//创建查询对象
Query query = new TermQuery(new Term(“content”, “spring”));

    //执行查询
    printResult(query, indexSearcher);

}

termQuery是根据关键词进行搜索,对要搜索的内容,没有分词的功能。

11.1.3 数值范围查询NumericRangeQuery
可以根据数值的范围进行查询。
//数值范围查询
@Test
public void testNumericRangeQuery() throws Exception {
IndexSearcher indexSearcher = getIndexSearcher();
//参数:1、指定要搜索的域 2、最小值 3、最大值 4、是否包含最小值 5、是否包含最大值
Query query = NumericRangeQuery.newLongRange(“size”, 0l, 1000l, true, true);
//执行查询
printResult(query, indexSearcher);
}

11.1.4 多条件组合查询BooleanQuery
//组合条件查询
@Test
public void testBooleanQuery() throws Exception {
IndexSearcher indexSearcher = getIndexSearcher();
//创建查询对象
BooleanQuery query = new BooleanQuery();
//创建查询的条件
Query query1 = new TermQuery(new Term(“name”, “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

11.2 QueryParser
需要把QueryParser依赖的jar包添加到工程中。

Lucene的常用操作详解,crud_第21张图片
可以使用QueryParser类进行查询,查询过程是先分词,分词后根据分词结果查询索引库。

//使用QueryParser查询
@Test
public void testQueryParser() throws Exception {
IndexSearcher indexSearcher = getIndexSearcher();

    //创建一个查询分析对象
    //参数1:默认搜索域,当不指定搜索的域时,就在默认域上进行搜索。
    //参数2:分析器对象。
    QueryParser queryParser = new QueryParser("content", new IKAnalyzer());
    Query query = queryParser.parse("lucene is a apache project");
    printResult(query, indexSearcher);

}

也可以使用查询语法进行查询:

11.2.1 查询语法:
1、基础的查询语法:
域名:关键词
例如:name:apache
如果指定搜索域就按照指定的域进行搜索,如果没有指定就使用默认的域。
2、匹配所有文档:
:
3、范围查询语法:
搜索域:[最小值 TO 最大值]
例如:size:{0 TO 1000]
{:不包含边界值
[:包含边界值
在Lucene中范围查询不支持数值类型,只支持字符串类型。如果想查询数组范围还需要使用NumericRangeQuery。在solr中是好用的。

4、组合条件查询语法:
1)添加必须满足,需要在条件前加上“+”
+name:apache +content:apache
name:apache AND content:apache

2)两个条件满足其中之一,或者的关系,条件前什么也没有。
name:apache content:apache
name:apache OR content:apache

3)如果是取非的关系,条件前添加一个“-”
-name:apache content:apache
name:apache NOT content:apache

11.3 MulitiFieldQueryParser
和QueryParser的区别就是可以指定多个默认搜索域。
@Test
public void testMultiFieldQueryParser() throws Exception {
IndexSearcher indexSearcher = getIndexSearcher();

    //创建一个查询分析对象
    //参数1:默认搜索域,当不指定搜索的域时,就在默认域上进行搜索。
    //参数2:分析器对象。
    //默认搜索域
    String[] fields = {"name","content"};
    MultiFieldQueryParser queryParser = new MultiFieldQueryParser(fields, new IKAnalyzer());
    Query query = queryParser.parse("lucene is a apache project");
    System.out.println(query);
    printResult(query, indexSearcher);

}

生成的查询语法:
(name:lucene content:lucene) (name:is content:is) (name:a content:a) (name:apache content:apache) (name:project content:project)

你可能感兴趣的:(Lucene,全文检索,结构)