热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Lucene学习-创建索引、关键词查询

Lucene是一个全文检索的开源软件,对需要查询的关键词进行检索1.需要的jar包lucene-analyzers-3.0.2.jarlucene-core-3.0.2.jarl

Lucene是一个全文检索的开源软件,对需要查询的关键词进行检索

1. 需要的jar包
  • lucene-analyzers-3.0.2.jar
  • lucene-core-3.0.2.jar
  • lucene-highlighter-3.0.2.jar
  • lucene-memory-3.0.2.jar

2. 编码步骤

2.1 准备Article文章类

public class Article {
private Integer id;
private String title;
private String content;

public Article(){}

public Article(Integer id, String title, String content) {
super();
this.id = id;
this.title = title;
this.cOntent= content;
}
@Override
public String toString() {
return "Article [id=" + id + ", title=" + title + ", cOntent="
+ content + "]";
}
//省略getter/setter方法
......
}

2.2 创建索引库

2.2.1 步骤

  1. 创建Article对象
  2. 创建Document对象
  3. 将Article对象的三个属性值绑定到Document对象中
  4. 创建IndexWriter字符流对象
  5. 将document对象写入lucene索引库
  6. 关闭indexWriter字符流对象

2.2.2 方法实例

/**
* 创建索引库
* 将Article对象放入索引库的原始记录中,形成词汇表
* @throws IOException
*/

@Test
public void createIndexDB() throws IOException{
// 1. 创建Article对象
Article article = new Article(1,"处理器","处理器是电脑的核心部件");
// 2. 创建Document对象
Document document = new Document();
// 3. 将Article对象的三个属性值绑定到Document对象中
/*
* 参数1:document对象中的属性名叫xid,article对象中的属性名为id,项目中建议相同
* 参数2:xid对应的article的属性id,注意必须转化为字符型
* 参数3:是否将xid属性值存入由原始记录表中转存入词汇表
* - Store.YES:表示该属性值会存入词汇表
* - Store.NO:表示该属性值不会存入词汇表
* 参数4:是否将xid属性进行分词算法
* - Index.ANALYZED:表示会对该属性进行词汇拆分
* - Index.NOT_ANALYZED:表示不会对该属性进行词汇拆分
* 项目中建议非 id 属性都进行分词拆分
*/

document.add(new Field("xid", article.getId().toString(),Store.YES,Index.ANALYZED));
document.add(new Field("xtitle", article.getTitle(),Store.YES,Index.ANALYZED));
document.add(new Field("xcontent", article.getContent(),Store.YES,Index.ANALYZED));

// 4. 创建IndexWriter字符流对象
Directory directory = FSDirectory.open(new File("D:/IndextDB"));
Version version = Version.LUCENE_30;
Analyzer analyzer = new StandardAnalyzer(version);
MaxFieldLength maxFieldLength = MaxFieldLength.LIMITED;
/*
* 参数1:Lucene索引库对应在磁盘的目录中,D:/IndextDB
* 参数2:采用什么策略将文本拆分,一个策略就是一个具体的实现类
* 参数3:最多将文本拆出来多少词汇,LIMITED表示1W个,即只取前1W个词汇,如果不足1W个词汇个,以实际为准
*/

IndexWriter indexWriter = new IndexWriter(directory, analyzer, maxFieldLength);
// 5. 将document对象写入lucene索引库
indexWriter.addDocument(document);
// 6. 关闭indexWriter字符流对象
indexWriter.close();
}

该方法执行后会在对应的磁盘创建索引库文件
这里写图片描述
此处有三个.cfs文件是因为下面创建了多个,下文会做解释

2.3 关键词检索

2.3.1 步骤

  1. 准备工作,创建需要查询的关键词(String类型)
  2. 创建接受结果的List
    集合
  3. 创建IndexSearcher字符流对象
  4. 创检QueryParser查询解析器对象
  5. 创建Query对象封装查询关键字
  6. 根据关键字,去索引库中查找相关词汇返回TopDocs索引号对象
  7. 迭代词汇表中符合条件的编号

2.3.2 方法实例

/**
* 根据关键字词从索引库中取出来符合条件的内容
* @throws IOException
* @throws ParseException
*/

@Test
public void findIndexDB() throws IOException, ParseException{
// 0. 准备工作,创建需要查询的关键词
String keyword = "处";
// 1. 创建接受结果的list集合
List
articleList = new ArrayList
();
Directory directory = FSDirectory.open(new File("D:/IndextDB"));
Version version = Version.LUCENE_30;
Analyzer analyzer = new StandardAnalyzer(version);
MaxFieldLength maxFieldLength = MaxFieldLength.LIMITED;

// 2. 创建IndexSearcher字符流对象
IndexSearcher indexSearcher = new IndexSearcher(directory);

// 3. 创检查询解析器对象
/*
* 参数一:使用分词器的版本,提倡使用最新的版本
* 参数二:对document对象中的哪一个属性进行搜索
* 参数三:参数解析器
* */

QueryParser queryParser = new QueryParser(version,"xcontent", analyzer);
// 4. 创建对象封装查询关键字
Query query = queryParser.parse(keyword);
// 5. 根据关键字,去索引库中查找相关词汇返回TopDocs索引号对象
/*
* 参数一:表示封装关键字查询对象,其它QueryParser表示查询解析器
* 参数二:MAX_RECORD表示如果根据关键字搜索出来的内容较多,只取前MAX_RECORD个内容
* 不足MAX_RECORD个数的话,以实际为准
* */

int MAX_RECORD = 100;
TopDocs topDocs = indexSearcher.search(query, MAX_RECORD);
// 6. 迭代词汇表中符合条件的编号
for(int i=0;i // 6.1 取出封装编号和分数的scoreDoc对象
ScoreDoc scoreDoc = topDocs.scoreDocs[i];
// 6.2 取出来每一个编号
int no = scoreDoc.doc;
// 6.3 根据编号去索引库中原始记录表中查询对应的document对象
Document document = indexSearcher.doc(no);
// 6.4 获取document对象的三个属性值
String xid = document.get("xid");
String xtitle = document.get("xtitle");
String xcOntent= document.get("xcontent");
// 6.5 封装到article对象中
Article article = new Article(Integer.parseInt(xid), xtitle, xcontent);
// 6.6 将article添加到list集合中
articleList.add(article);
}
}

输出查询结果:

Article [id=1, title=处理器, cOntent=处理器是电脑的核心部件]

3. Lucene查询的优化

3.1 创建工具类

上面的代码步骤繁多,看起来都很麻烦,我们把常用的和冗余的代码抽取出来,封装到工具类中,可以是代码更简洁。
该工具类用到了 java.lang.reflect 反射包

package com.bart.lucene.util;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

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.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.junit.Test;

import com.bart.lucene.entity.Article;

/**
* 封装常用的操作
* @author bart
*
*/

public class LuceneUtils {

private static Directory directory;//Lucene索引库对应在磁盘的目录中,D:/IndextDB
private static Version version;//版本号
private static Analyzer analyzer;//采用什么策略将文本拆分,一个策略就是一个具体的实现类
private static MaxFieldLength maxFieldLength;//默认1W条记录

static{
try {
directory = FSDirectory.open(new File("E:/IndexDBDBDB"));
version = Version.LUCENE_30;
analyzer = new StandardAnalyzer(version);
maxFieldLength = MaxFieldLength.LIMITED;
} catch (Exception e) {
e.printStackTrace();
//手动抛出运行时异常
throw new RuntimeException(e);
}
}

public static Directory getDirectory() {
return directory;
}

public static Version getVersion() {
return version;
}

public static Analyzer getAnalyzer() {
return analyzer;
}

public static MaxFieldLength getMaxFieldLength() {
return maxFieldLength;
}

//私有的构造方法,防止外部new来
private LuceneUtils(){}

/**
* JavaBean转化为Document对象
* @param object
* @return Document
* @throws Exception
*/

public static Document javaBean2Document(Object obj) throws Exception{
Document document = new Document();
// 1. 获取obj的字节码
Class clazz = obj.getClass();
// 2. 获取私有属性
Field[] fields = clazz.getDeclaredFields();
// 3. 迭代私有属性
for(Field field : fields){
// 3.1 设置允许访问,强力反射,提高速度
field.setAccessible(true);
// 3.2 获取属性名
String name = field.getName();
// 3.3 拼接方法名 getId()/getTitle()
String methodName = "get"+name.substring(0, 1).toUpperCase()+name.substring(1);
// 3.4 获取方法,(方法名,参数名)
Method method = clazz.getMethod(methodName,null);
// 3.5 执行方法,获得返回值
String value = method.invoke(obj,null).toString();
// // 3.6 添加到document对象中
document.add(new org.apache.lucene.document.Field(name,value,Store.YES,Index.ANALYZED));
}
return document;
}

/**
* document对象转化为javabean对象
* @param document
* @param clazz
* @return t
* @throws Exception
*/

public static T document2JavaBean(Document document,Classclazz) throws Exception{
// 1. 创建对应的实例
T t = clazz.newInstance();
// 2. 通过反射得到私有成员变量
Field[] fields = clazz.getDeclaredFields();
// 3. 遍历私有成员变量
for(Field field : fields){
// 3.1 得到成员变量名
String name = field.getName();
// 3.2 得到document中的成员变量值
String value = document.get(name);
// 3.3 使用BeanUtils.setProperty(类实例,变量名,变量值)
BeanUtils.setProperty(t, name, value);
}
return t;
}

//测试
public static void main(String[] args) throws Exception{
Article article = new Article(1, "处理器","处理器是一台电子计算机的重要部件");
Document document = LuceneUtils.javaBean2Document(article);
System.out.println(document.toString());
System.out.println("---------");
Article article2 = LuceneUtils.document2JavaBean(document, Article.class);
System.out.println(article2);
}
}

3.2 重构FirstApp类

使用封装的工具类重构FirstApp.java

3.2.1 创建索引库

@Test
public void createIndexDB() throws Exception{
// 1. 创建Article对象
//Article article = new Article(1,"处理器","处理器是电脑的核心部件");
//Article article = new Article(2,"显卡","显卡是电脑的显示输出部件");
Article article = new Article( 3,"内存条","内存条是电脑的核心部件之一");
// 2. 用LuceneUtils工具类的方法获得Document对象
Document document = LuceneUtils.javaBean2Document(article);
// 3. 创建IndexWriter字符流对象
IndexWriter indexWriter = new IndexWriter(LuceneUtils.getDirectory(),LuceneUtils.getAnalyzer(),LuceneUtils.getMaxFieldLength());
// 4. indexWriter对象写入document对象
indexWriter.addDocument(document);
// 5. 关闭indexWriter流
indexWriter.close();
}

因为此处创建了三个Article都放在了索引库中,故此在2.2.2中的图中三个.cfs文件。

3.2.2 根据关键词查询

 @Test
public void findIndexDB() throws Exception{
// 1. 创建keyword
//准备工作
String keyword = "显卡";
List
articleList = new ArrayList
();
// 2. 创建indexSearcher
IndexSearcher indexSearcher = new IndexSearcher(LuceneUtils.getDirectory());
// 3. 创检查询解析器对象
QueryParser queryParser = new QueryParser(LuceneUtils.getVersion(),"content",LuceneUtils.getAnalyzer());
// 4. 创建对象封装查询关键字
Query query = queryParser.parse(keyword);
// 5. 查询
int MAX_RECORD=100;
TopDocs topDocs = indexSearcher.search(query, MAX_RECORD);
// 6. 迭代词汇表中符合条件的编号
for(int i=0;i // 6.1 取出封装编号和分数的scoreDoc对象
ScoreDoc scoreDoc = topDocs.scoreDocs[i];
// 6.2 取出来每一个编号
int no = scoreDoc.doc;
// 6.3 根据编号去索引库中原始记录表中查询对应的document对象
Document document = indexSearcher.doc(no);
// 6.4 利用工具类将document对象转化为article对象
Article article = LuceneUtils.document2JavaBean(document, Article.class);
// 6.5 将查询到的article对象添加到list集合中
articleList.add(article);
}
//遍历结果
for(Article article : articleList){
System.out.println(article);
}

}

输出结果:

Article [id=2, title=显卡, cOntent=显卡是电脑的显示输出部件]

哈哈,作为一个卡巴司机,当然首先查询一下显卡了。

总结

我们发现代码重构之后,代码简洁了很多,而且工具的重用性更强了。在之后的项目中可以导包,直接调用。


推荐阅读
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • Android系统移植与调试之如何修改Android设备状态条上音量加减键在横竖屏切换的时候的显示于隐藏
    本文介绍了如何修改Android设备状态条上音量加减键在横竖屏切换时的显示与隐藏。通过修改系统文件system_bar.xml实现了该功能,并分享了解决思路和经验。 ... [详细]
  • Python爬虫中使用正则表达式的方法和注意事项
    本文介绍了在Python爬虫中使用正则表达式的方法和注意事项。首先解释了爬虫的四个主要步骤,并强调了正则表达式在数据处理中的重要性。然后详细介绍了正则表达式的概念和用法,包括检索、替换和过滤文本的功能。同时提到了re模块是Python内置的用于处理正则表达式的模块,并给出了使用正则表达式时需要注意的特殊字符转义和原始字符串的用法。通过本文的学习,读者可以掌握在Python爬虫中使用正则表达式的技巧和方法。 ... [详细]
author-avatar
敦恒
招聘!招聘!招聘! 联系方式:56226135/shiziqian@hy9z.com 请优先邮件联系~谢谢!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有