Lucene全文检索大体分两个部分:索引创建(Indexing)和搜索索引(Search)
1. 索引过程
1) 有一系列被索引文件(此处所指即文本数据)
2) 被索引文件经过语法分析和语言处理形成一系列词(Term)。
3) 经过索引创建形成词典和反向索引表。
4) 通过索引存储将索引写入硬盘。
2. 搜索过程
1) 用户输入查询语句。
2) 对查询语句经过语法分析和语言分析得到一系列词(Term)。
3) 通过语法分析得到一个查询树。
4) 通过索引存储将索引读入到内存。
5) 利用查询树搜索索引,从而得到每个词(Term)的文档链表,对文档链表进行交,差,并得到结果文档。
6) 将搜索到的结果文档对查询的相关性进行排序。
7) 返回查询结果给用户。
Lucene目前版本5.2.1,下面我们以这个版本演示一下Lucene的使用代码。
下面我们以一个实例说明:
引入依赖包:
<properties> <lucene.version>5.2.1</lucene.version> </properties> <dependencies> <dependency> <groupId> org.apache.lucene</groupId> <artifactId> lucene-core</artifactId> <version> ${lucene.version}</version> </dependency> <dependency> <groupId> org.apache.lucene</groupId> <artifactId> lucene-analyzers-common</artifactId> <version> ${lucene.version}</version> </dependency> <dependency> <groupId> org.apache.lucene</groupId> <artifactId> lucene-queryparser</artifactId> <version> ${lucene.version}</version> </dependency> </dependencies>实例对象:
package cn.slimsmart.lucene.demo.example; import java.util.ArrayList; import java.util.List; public class User { private String id; private String name; private String desc; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public static List<User> getInitList(){ List<User> list = new ArrayList<User>(); User user = new User(); user.setId("10001"); user.setName("张三"); user.setDesc("张三是个农民,勤劳致富,奔小康"); list.add(user); user = new User(); user.setId("20001"); user.setName("李四"); user.setDesc("李四是个企业家,白手起家,致富一方"); list.add(user); user = new User(); user.setId("11111"); user.setName("王五"); user.setDesc("王五好吃懒做,溜须拍马,跟着李四,也过着小康的日子"); list.add(user); return list; } }使用实例:
package cn.slimsmart.lucene.demo.example; import java.io.File; import java.nio.file.Paths; 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.Store; import org.apache.lucene.document.StringField; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.index.IndexWriterConfig.OpenMode; import org.apache.lucene.index.Term; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TopDocs; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; public class Test { public static void main(String[] args) throws Exception { createIndex(); search(); } public static void createIndex() throws Exception { String pathFile = new File("src/main/resources").getAbsolutePath(); // 索引文件的保存位置 Directory dir = FSDirectory.open(Paths.get(pathFile)); // 分析器 Analyzer analyzer = new StandardAnalyzer(); // 配置类 IndexWriterConfig iwc = new IndexWriterConfig(analyzer); /** APPEND:总是追加,可能会导致错误,索引还会重复,导致返回多次结果 CREATE:清空重建(推荐) CREATE_OR_APPEND【默认】:创建或追加 */ iwc.setOpenMode(OpenMode.CREATE);// 创建模式 OpenMode.CREATE_OR_APPEND 添加模式 IndexWriter writer = new IndexWriter(dir, iwc); for (User u : User.getInitList()) { Document doc = new Document(); doc.add(new StringField("id", u.getId(), Store.YES)); doc.add(new StringField("name",u.getName(), Store.YES)); doc.add(new StringField("desc", u.getDesc(), Store.YES)); System.out.println(doc); writer.addDocument(doc); } System.out.println("初始化完毕"); writer.commit(); writer.close(); } public static void search() throws Exception { String pathFile = new File("src/main/resources").getAbsolutePath(); Directory dir = FSDirectory.open(Paths.get(pathFile)); IndexReader reader=DirectoryReader.open(dir); IndexSearcher searcher=new IndexSearcher(reader); //对于中文查询,需要分词 Term term=new Term("name", "张三"); Query query= new TermQuery(term); //模糊搜索 //Term term=new Term("desc", "*小康*"); //Query query= new WildcardQuery(term); //n 查找top TopDocs topdocs=searcher.search(query, 2); ScoreDoc[] scoreDocs=topdocs.scoreDocs; System.out.println("查询结果总数:" + topdocs.totalHits); System.out.println("最大的评分:"+topdocs.getMaxScore()); for(int i=0; i < scoreDocs.length; i++) { int doc = scoreDocs[i].doc; Document document = searcher.doc(doc); System.out.println("docid:" + scoreDocs[i].doc); System.out.println("scors:" + scoreDocs[i].score); System.out.println("shardIndex:" + scoreDocs[i].shardIndex); System.out.println("id:"+document.get("id")+",name:"+document.get("name")+",desc:"+document.get("desc")); } reader.close(); } }运行可以看到:
初始化完毕 查询结果总数:1 最大的评分:1.4054651 docid:0 scors:1.4054651 shardIndex:0 id:10001,name:张三,desc:张三是个农民,勤劳致富,奔小康
注:由于lucene自带的分词方式对中文分词十分的不友好,所以在对一段中文中的某个词组进行搜索时,需要在创建索引是对其进行分词,如搜索desc中的“致富”,无法获取结果。
参考文章:
1.Lucene:基于Java的全文检索引擎简介
2.Lucene原理与代码分析