【Lucene学习笔记】基本使用和认识
一、Lucene是什么
这个在之前转载的2篇相关博文中已经介绍的很清晰了,包括一些基本概念什么的,在这篇笔记里我就不多赘述了,简单来说Lucene就是一个开放源代码的全文检索引擎工具包,即它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎。目前最新的是4.10.2版本,所以我使用的是这个版本来进行学习实验的。
二、基本用法
1. 索引的建立
索引的建立一般为以下6个固定步骤:
① 创建Directory
② 创建IndexWriter
③ 创建Document对象
④ 为Document对象添加Field
⑤ 通过IndexWriter添加文档到索引中
⑥ 关闭IndexWriter和Directory
下面直接给出程序作为例子(此例使用文本文件进行索引建立):
package test;
import java.io.File;
import java.io.FileReader;
import java.io.Reader;
import java.util.Date;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
/**
* This class demonstrate the process of creating index with Lucene
* for text files
*/
public class TxtFileIndexer {
public static void main(String[] args) throws Exception{
//1、创建Directory
Directory directory = FSDirectory.open(new File("F:\\luceneIndex"));
Analyzer luceneAnalyzer = new StandardAnalyzer(Version.LUCENE_CURRENT);
//2、创建IndexWriter
IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_CURRENT,luceneAnalyzer);
IndexWriter indexWriter = new IndexWriter(directory, config);
long startTime = new Date().getTime();
//dataDir is the directory that hosts the text files that to be indexed
File dataDir = new File("F:\\luceneData");
File[] dataFiles = dataDir.listFiles();
for(int i = 0; i < dataFiles.length; i++){
if(dataFiles[i].isFile() && dataFiles[i].getName().endsWith(".txt")){
System.out.println("Indexing file " + dataFiles[i].getCanonicalPath());
//3、创建Document对象
Document document = new Document();
Reader txtReader = new FileReader(dataFiles[i]);
//4、为Document对象添加Field
document.add(new Field("num",""+(i+1),StringField.TYPE_STORED));
document.add(new Field("content",txtReader,TextField.TYPE_NOT_STORED));
document.add(new Field("path",dataFiles[i].getCanonicalPath(),StringField.TYPE_STORED));
String title = dataFiles[i].getName();
document.add(new Field("title",title.substring(0, title.length()-4),TextField.TYPE_STORED));
//5、通过IndexWriter添加文档到索引中
indexWriter.addDocument(document);
}
}
//6、关闭IndexWriter和Directory
indexWriter.close();
directory.close();
long endTime = new Date().getTime();
System.out.println("It takes " + (endTime - startTime)
+ " milliseconds to create index for the files in directory "
+ dataDir.getPath());
}
}
2. 查询的使用
查询的使用一般为以下8个固定步骤:
① 创建Directory
② 根据Directory创建IndexReader
③ 根据IndexReader创建IndexSearcher
④ 创建QueryParser对象
⑤ 创建搜索的Query
⑥ 根据Searcher搜索返回TopDocs然后获取ScoreDoc
⑦ 根据ScoreDoc获取具体Document对象并得到所需值
⑧ 关闭IndexReader和Directory
下面给出程序作为例子(使用索引建立程序建立的索引进行):
package test;
import java.io.File;
import java.util.Scanner;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
/**
* This class is used to demonstrate the
* process of searching on an existing
* Lucene index
*
*/
public class TxtFileSearcher {
public static void main(String[] args) throws Exception{
//1、创建Directory
File indexDir = new File("F:\\luceneIndex");
FSDirectory directory = FSDirectory.open(indexDir);
//2、根据Directory创建DirectoryReader
DirectoryReader reader = DirectoryReader.open(directory);
//3、根据IndexReader创建IndexSearcher
IndexSearcher searcher = new IndexSearcher(reader);
//4、创建QueryParser对象
Analyzer luceneAnalyzer = new StandardAnalyzer(Version.LUCENE_CURRENT);
QueryParser parser = new QueryParser(Version.LUCENE_CURRENT, "content", luceneAnalyzer);
if(!indexDir.exists()){
System.out.println("The Lucene index is not exist");
return;
}
int n = 10;
while(n--!=0) {
Scanner readScanner = new Scanner(System.in);
String str = readScanner.nextLine();
//5、创建搜索的Query
Query query = parser.parse(str);
//6、根据Searcher搜索返回TopDocs然后获取ScoreDoc
ScoreDoc[] sd = searcher.search(query,1000).scoreDocs;
System.out.println("查找共有"+sd.length+"个结果");
//7、根据ScoreDoc获取具体Document对象并得到所需值
for (int i = 0; i < sd.length; i++) {
Document doc = searcher.doc(sd[i].doc);
System.out.println(doc.get("title")+" : "+doc.get("path"));
}
}
//8、关闭IndexReader和Directory
reader.close();
directory.close();
}
}
三、一些高级搜索
Lucene支持多种形式的高级搜索,并且有相关的API实现,不过目前的Lucene版本可以利用QueryParse就能转换这些高级搜索功能,这里只使用上面的程序进行一个测试,至于具体的细节在以后仔细琢磨后再做总结吧。
luceneData文件:
test01.txt:Tom lives in Guangzhou,I live in Guangzhou too.
test02.txt:He once lived in Shanghai. Now, he lives in Guangzhou.
1. 布尔操作符
大多数的搜索引擎都会提供布尔操作符让用户可以组合查询,典型的布尔操作符有 AND, OR, NOT。Lucene 支持 5 种布尔操作符,分别是 AND, OR, NOT, 加(+), 减(-)。
- OR: 如果你要搜索含有字符 A 或者 B 的文档,那么就需要使用 OR 操作符。需要记住的是,如果你只是简单的用空格将两个关键词分割开,其实在搜索的时候搜索引擎会自动在两个关键词之间加上 OR 操作符。例如,“Java OR Lucene” 和 “Java Lucene” 都是搜索含有 Java 或者含有 Lucene 的文档。
- AND: 如果你需要搜索包含一个以上关键词的文档,那么就需要使用 AND 操作符。例如,“Java AND Lucene” 返回所有既包含 Java 又包含 Lucene 的文档。
- NOT: Not 操作符使得包含紧跟在 NOT 后面的关键词的文档不会被返回。例如,如果你想搜索所有含有 Java 但不含有 Lucene 的文档,你可以使用查询语句 “Java NOT Lucene”。但是你不能只对一个搜索词使用这个操作符,比如,查询语句 “NOT Java” 不会返回任何结果。
- 加号(+): 这个操作符的作用和 AND 差不多,但它只对紧跟着它的一个搜索词起作用。例如,如果你想搜索一定包含 Java,但不一定包含 Lucene 的文档,就可以使用查询语句“+Java Lucene”。
- 减号(-): 这个操作符的功能和 NOT 一样,查询语句 “Java -Lucene” 返回所有包含 Java 但不包含 Lucene 的文档。
2. 域搜索
Lucene 支持域搜索,你可以指定一次查询是在哪些域(Field)上进行。例如,如果索引的文档包含两个域,Title
和Content
,你就可以使用查询 “Title: Lucene AND Content: Java” 来返回所有在 Title域上包含 Lucene 并且在 Content 域上包含 Java 的文档。
3. 通配符搜索
Lucene 支持两种通配符:问号(?)和星号(*)。你可以使用问号(?)来进行单字符的通配符查询,或者利用星号(*)进行多字符的通配符查询。例如,如果你想搜索 tiny 或者 tony,你就可以使用查询语句 “t?ny”;如果你想查询 Teach, Teacher 和 Teaching,你就可以使用查询语句 “Teach*”。
4. 模糊查询
Lucene 提供的模糊查询基于编辑距离算法(Edit distance algorithm)。你可以在搜索词的尾部加上字符 ~ 来进行模糊查询。例如,查询语句 “think~” 返回所有包含和 think 类似的关键词的文档。
5. 测试范围搜索
范围搜索匹配某个域上的值在一定范围的文档。例如,查询 “age:[18 TO 35]” 返回所有 age 域上的值在 18 到 35 之间的文档。
四、小结
这里对很多的细节没有做太多的说明,这里只是对Lucene的一些基本功能简单实现了一下,因为自己才刚刚开始学习Lucene,很多东西也还在学习的过程中,目前使用的版本是4.10.2,到网上找的很多资料版本都不太高,所以其中有很多变动的东西需要去看说明文档等。这里值得一说的是索引建立的new Field()方法中FieldType这一项中的各个参数,是否索引和是否分词都比较好理解,对于是否存储这一项的意思其实是在索引中是否存储这一个域中的信息,如果存储则可以在查询是使用document对象直接用get方法得到对应的信息,否则需要通过其他信息找到源文件后再进行提取,这个是否存储就取决于此域中信息的性质了,像content之类一般是不会进行存储的。
参考文献:http://blog.csdn.net/zhch152/article/details/8210993
本文固定连接:http://blog.csdn.net/fyfmfof/article/details/41991171