Lucene 4.7 学习及实例demo
很早就听说Lucene的大名了,但一直没空研究,今天抽了一个下午时间,学习了一下Lucene,写了一个简单的Demo,总的感受是使用起来简单方便,在使用之前,首先要理解以下关键的类:
Document
Document 是用来描述文档的,这里的文档可以指一个 HTML 页面,一封电子邮件,或者是一个文本文件。一个 Document 对象由多个 Field 对象组成的。可以把一个 Document 对象想象成数据库中的一个记录,而每个 Field 对象就是记录的一个字段。
Field
Field 对象是用来描述一个文档的某个属性的,比如一封电子邮件的标题和内容可以用两个 Field 对象分别描述。
Analyzer
在一个文档被索引之前,首先需要对文档内容进行分词处理,这部分工作就是由 Analyzer 来做的。Analyzer 类是一个抽象类,它有多个实现。针对不同的语言和应用需要选择适合的 Analyzer。Analyzer 把分词后的内容交给 IndexWriter 来建立索引。
IndexWriter
IndexWriter 是 Lucene 用来创建索引的一个核心的类,他的作用是把一个个的 Document 对象加到索引中来。
Directory
这个类代表了 Lucene 的索引的存储的位置,这是一个抽象类,它目前有两个实现,第一个是 FSDirectory,它表示一个存储在文件系统中的索引的位置。第二个是 RAMDirectory,它表示一个存储在内存当中的索引的位置。
Query
这是一个抽象类,他有多个实现,比如 TermQuery, BooleanQuery, PrefixQuery. 这个类的目的是把用户输入的查询字符串封装成 Lucene 能够识别的 Query。
IndexSearcher
IndexSearcher 是用来在建立好的索引上进行搜索的。它只能以只读的方式打开一个索引,所以可以有多个 IndexSearcher 的实例在一个索引上进行操作。
Hits
Hits 是用来保存搜索结果的。
理解了这些类之后,我写了一个简单的demo,包括索引构建和索引搜索,以后如果要做复杂的搜索,可以根据这个demo做扩展,是不是很简单哈。
1 import java.io.File; 2 import java.io.IOException; 3 import java.util.ArrayList; 4 import java.util.List; 5 import org.apache.lucene.analysis.Analyzer; 6 import org.apache.lucene.analysis.standard.StandardAnalyzer; 7 import org.apache.lucene.document.Document; 8 import org.apache.lucene.document.Field; 9 import org.apache.lucene.document.TextField; 10 import org.apache.lucene.index.DirectoryReader; 11 import org.apache.lucene.index.IndexWriter; 12 import org.apache.lucene.index.IndexWriterConfig; 13 import org.apache.lucene.queryparser.classic.MultiFieldQueryParser; 14 import org.apache.lucene.search.IndexSearcher; 15 import org.apache.lucene.search.Query; 16 import org.apache.lucene.search.ScoreDoc; 17 import org.apache.lucene.store.Directory; 18 import org.apache.lucene.store.FSDirectory; 19 import org.apache.lucene.util.Version; 20 21 /** 22 * Lucene Demo 23 * Author: herui 24 * DateTime: 2014-3-31 下午3:39:54 25 */ 26 public class LuceneDemo { 27 28 /** 29 * 根据内容,构建索引 30 * @param analyzer 31 * @param directory 32 * @param items 33 * @return 34 */ 35 private boolean buildIndexer(Analyzer analyzer, Directory directory, List<Item> items) { 36 IndexWriter iwriter = null; 37 try { 38 // 配置索引 39 iwriter = new IndexWriter(directory, new IndexWriterConfig( 40 Version.LUCENE_47, analyzer)); 41 // 删除所有document 42 iwriter.deleteAll(); 43 // 将文档信息存入索引 44 Document doc[] = new Document[items.size()]; 45 for (int i = 0; i < items.size(); i++) { 46 doc[i] = new Document(); 47 48 Item item = items.get(i); 49 java.lang.reflect.Field[] fields = item.getClass().getDeclaredFields(); 50 for (java.lang.reflect.Field field : fields) { 51 String fieldName = field.getName(); 52 String getMethodName = "get"+toFirstLetterUpperCase(fieldName); 53 Object obj = item.getClass().getMethod(getMethodName).invoke(item); 54 doc[i].add(new Field(fieldName, (String)obj, TextField.TYPE_STORED)); 55 } 56 57 iwriter.addDocument(doc[i]); 58 } 59 } catch (Exception e) { 60 e.printStackTrace(); 61 return false; 62 } finally { 63 try { 64 iwriter.close(); 65 } catch (IOException e) { 66 } 67 } 68 return true; 69 } 70 71 /** 72 * 根据keyword搜索索引 73 * @param analyzer 74 * @param directory 75 * @param keyword 76 * @return 77 */ 78 public List<Item> searchIndexer(Analyzer analyzer, Directory directory, String keyword) { 79 DirectoryReader ireader = null; 80 List<Item> result = new ArrayList<Item>(); 81 try { 82 // 设定搜索目录 83 ireader = DirectoryReader.open(directory); 84 IndexSearcher isearcher = new IndexSearcher(ireader); 85 86 // 对多field进行搜索 87 java.lang.reflect.Field[] fields = Item.class.getDeclaredFields(); 88 int length = fields.length; 89 String[] multiFields = new String[length]; 90 for (int i = 0; i < length; i++) { 91 multiFields[i] = fields[i].getName(); 92 } 93 MultiFieldQueryParser parser = new MultiFieldQueryParser( 94 Version.LUCENE_47, multiFields, analyzer); 95 96 // 设定具体的搜索词 97 Query query = parser.parse(keyword); 98 ScoreDoc[] hits = isearcher.search(query, null, 10).scoreDocs; 99 100 for (int i = 0; i < hits.length; i++) { 101 Document hitDoc = isearcher.doc(hits[i].doc); 102 Item item = new Item(); 103 for (String field : multiFields) { 104 String setMethodName = "set"+toFirstLetterUpperCase(field); 105 item.getClass().getMethod(setMethodName, String.class).invoke(item, hitDoc.get(field)); 106 } 107 result.add(item); 108 } 109 } catch (Exception e) { 110 e.printStackTrace(); 111 return null; 112 } finally { 113 try { 114 ireader.close(); 115 directory.close(); 116 } catch (IOException e) { 117 } 118 } 119 return result; 120 } 121 122 /** 123 * 首字母转大写 124 * @param str 125 * @return 126 */ 127 public static String toFirstLetterUpperCase(String str) { 128 if(str == null || str.length() < 2){ 129 return str; 130 } 131 return str.substring(0, 1).toUpperCase() + str.substring(1, str.length()); 132 } 133 134 public static void main(String[] args) throws Exception { 135 LuceneDemo demo = new LuceneDemo(); 136 Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_47); 137 138 List<Item> items = new ArrayList<Item>(); 139 items.add(new Item("1", "first", "This is the text to be greatly indexed.")); 140 items.add(new Item("2", "second", "This is great")); 141 items.add(new Item("3", "third", "I love apple and pear. ")); 142 items.add(new Item("4", "four", "我是中国人")); 143 items.add(new Item("5", "five", "我叫何瑞")); 144 145 // 索引存到内存中的目录 146 //Directory directory = new RAMDirectory(); 147 // 索引存储到硬盘 148 File file = new File("d:/lucene"); 149 Directory directory = FSDirectory.open(file); 150 demo.buildIndexer(analyzer, directory, items); 151 List<Item> result = demo.searchIndexer(analyzer, directory, "中国"); 152 153 for (Item item : result) { 154 System.out.println(item.toString()); 155 } 156 } 157 }
Item.java
1 public class Item { 2 3 private String id; 4 private String title; 5 private String content; 6 7 public Item() { 8 } 9 10 public Item(String id, String title, String content) { 11 this.id = id; 12 this.title = title; 13 this.content = content; 14 } 15 16 public String getId() { 17 return id; 18 } 19 public void setId(String id) { 20 this.id = id; 21 } 22 public String getTitle() { 23 return title; 24 } 25 public void setTitle(String title) { 26 this.title = title; 27 } 28 public String getContent() { 29 return content; 30 } 31 public void setContent(String content) { 32 this.content = content; 33 } 34 35 public String toString() { 36 StringBuilder sb = new StringBuilder(); 37 sb.append("[id=").append(id).append(",title=").append(title) 38 .append(",content=").append(content).append("]"); 39 return sb.toString(); 40 } 41 }