我们的Lucene程序就是大概这么一个思路:将JavaBean对象封装到Document对象中,然后通过IndexWriter把document写入到索引库中。当用户需要查询的时候,就使用IndexSearcher从索引库中读取数据,找到对应的Document对象,从而解析里边的内容,再封装到JavaBean对象中让我们使用。
二、对Lucene代码优化
我们再次看回我们上一篇快速入门写过的代码,我来截取一些有代表性的:
以下代码在把数据填充到索引库,和从索引库查询数据的时候,都出现了。是重复代码!
Directory directory = FSDirectory.open(new File("E:/createIndexDB"));
//使用标准的分词算法对原始记录表进行拆分
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
以下的代码其实就是将JavaBean的数据封装到Document对象中,我们是可以通过反射来对其进行封装….如果不封装的话,我们如果有很多JavaBean都要添加到Document对象中,就会出现很多类似的代码。
//将Document对象中的所有属性取出,再封装回JavaBean对象中去
String id = document.get("id");
String userName = document.get("userName");
String sal = document.get("sal");
User user = new User(id, userName, sal);
2.1编写Lucene工具类
在编写工具类的时候,值得注意的地方:
当我们得到了对象的属性的时候,就可以把属性的get方法封装起来
得到get方法,就可以调用它,得到对应的值
在操作对象的属性时,我们要使用暴力访问
如果有属性,值,对象这三个变量,我们记得使用BeanUtils组件
import org.apache.commons.beanutils.BeanUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.junit.Test;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* Created by ozc on 2017/7/12.
*/
/**
* 使用单例事例模式
* */
public class LuceneUtils {
private static Directory directory;
private static Analyzer analyzer;
private static IndexWriter.MaxFieldLength maxFieldLength;
private LuceneUtils() {}
static{
try {
directory = FSDirectory.open(new File("E:/createIndexDB"));
analyzer = new StandardAnalyzer(Version.LUCENE_30);
maxFieldLength = IndexWriter.MaxFieldLength.LIMITED;
} catch (Exception e) {
e.printStackTrace();
}
}
public static Directory getDirectory() {
return directory;
}
public static Analyzer getAnalyzer() {
return analyzer;
}
public static IndexWriter.MaxFieldLength getMaxFieldLength() {
return maxFieldLength;
}
/**
* @param object 传入的JavaBean类型
* @return 返回Document对象
*/
public static Document javaBean2Document(Object object) {
try {
Document document = new Document();
//得到JavaBean的字节码文件对象
Class<?> aClass = object.getClass();
//通过字节码文件对象得到对应的属性【全部的属性,不能仅仅调用getFields()】
Field[] fields = aClass.getDeclaredFields();
//得到每个属性的名字
for (Field field : fields) {
String name = field.getName();
//得到属性的值【也就是调用getter方法获取对应的值】
String method = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
//得到对应的值【就是得到具体的方法,然后调用就行了。因为是get方法,没有参数】
Method aClassMethod = aClass.getDeclaredMethod(method, null);
String value = aClassMethod.invoke(object).toString();
System.out.println(value);
//把数据封装到Document对象中。
document.add(new org.apache.lucene.document.Field(name, value, org.apache.lucene.document.Field.Store.YES, org.apache.lucene.document.Field.Index.ANALYZED));
}
return document;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* @param aClass 要解析的对象类型,要用户传入进来
* @param document 将Document对象传入进来
* @return 返回一个JavaBean
*/
public static Object Document2JavaBean(Document document, Class aClass) {
try {
//创建该JavaBean对象
Object obj = aClass.newInstance();
//得到该JavaBean所有的成员变量
Field[] fields = aClass.getDeclaredFields();
for (Field field : fields) {
//设置允许暴力访问
field.setAccessible(true);
String name = field.getName();
String value = document.get(name);
//使用BeanUtils把数据封装到Bean中
BeanUtils.setProperty(obj, name, value);
}
return obj;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Test
public void test() {
User user = new User();
LuceneUtils.javaBean2Document(user);
}
}
2.2使用LuceneUtils改造程序
@Test
public void createIndexDB() throws Exception {
//把数据填充到JavaBean对象中
User user = new User("2", "钟福成2", "未来的程序员2");
Document document = LuceneUtils.javaBean2Document(user);
/**
* IndexWriter将我们的document对象写到硬盘中
*
* 参数一:Directory d,写到硬盘中的目录路径是什么
* 参数二:Analyzer a, 以何种算法来对document中的原始记录表数据进行拆分成词汇表
* 参数三:MaxFieldLength mfl 最多将文本拆分出多少个词汇
*
* */
IndexWriter indexWriter = new IndexWriter(LuceneUtils.getDirectory(), LuceneUtils.getAnalyzer(), LuceneUtils.getMaxFieldLength());
//将Document对象通过IndexWriter对象写入索引库中
indexWriter.addDocument(document);
//关闭IndexWriter对象
indexWriter.close();
}
@Test
public void findIndexDB() throws Exception {
//创建IndexSearcher对象
IndexSearcher indexSearcher = new IndexSearcher(LuceneUtils.getDirectory());
//创建QueryParser对象
QueryParser queryParser = new QueryParser(Version.LUCENE_30, "userName", LuceneUtils.getAnalyzer());
//给出要查询的关键字
String keyWords = "钟";
//创建Query对象来封装关键字
Query query = queryParser.parse(keyWords);
//用IndexSearcher对象去索引库中查询符合条件的前100条记录,不足100条记录的以实际为准
TopDocs topDocs = indexSearcher.search(query, 100);
//获取符合条件的编号
for (int i = 0; i < topDocs.scoreDocs.length; i++) {
ScoreDoc scoreDoc = topDocs.scoreDocs[i];
int no = scoreDoc.doc;
//用indexSearcher对象去索引库中查询编号对应的Document对象
Document document = indexSearcher.doc(no);
//将Document对象中的所有属性取出,再封装回JavaBean对象中去
User user = (User) LuceneUtils.Document2JavaBean(document, User.class);
System.out.println(user);
}
}