本文共 4749 字,大约阅读时间需要 15 分钟。
什么是Lucene?
Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包,由资深全文检索专家Doug Cutting所撰写,它是一个全文检索引擎的架构,提供了完整的创建索引和查询索引,以及部分文本分析的引擎,Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎,Lucene在全文检索领域是一个经典的祖先,现在很多检索引擎都是在其基础上创建的,思想是相通的。
即:Lucene是根据关健字来搜索的文本搜索工具,只能在某个网站内部搜索文本内容,不能跨网站搜索
Lucene通常用在什么地方?
Lucene通常用在站内搜索中,例如:
Lucene在MVC的位置是dao层
Lucene存的是什么内容?
Lucene中存的就是一系列的二进制压缩文件和一些控制文件,它们位于计算机的硬盘上,
这些内容统称为索引库,索引库有二部份组成:
(1)原始记录
存入到索引库中的原始文本,例如:中国好室友,没错,正是在下
(2)词汇表
按照一定的拆分策略(即分词器)将原始记录中的每个字符拆开后,存入一个供将来搜索的表
为何网站的内部搜索要使用Lucene而不使用SQL?
(1)SQL只能针对的文本搜索
(2)SQL没有相关度排名
(3)SQL搜索结果没有关健字高亮显示
(4)SQL需要数据库的支持,数据库本身需要内存开销较大,例如:Oracle
(5)SQL搜索有时较慢,尤其是数据库不在本地时,超慢,例如:Oracle
如何使用?
流程如下:
创建索引库:
1) 创建JavaBean对象
2) 创建Docment对象
3) 将JavaBean对象所有的属性值,均放到Document对象中去,属性名可以和JavaBean相同或不同
4) 创建IndexWriter对象
5) 将Document对象通过IndexWriter对象写入索引库中
6) 关闭IndexWriter对象
根据关键字查询索引库中的内容:
1) 创建IndexSearcher对象
2) 创建QueryParser对象
3) 创建Query对象来封装关键字
4) 用IndexSearcher对象去索引库中查询符合条件的前100条记录,不足100条记录的以实际为准
5) 获取符合条件的编号
6) 用indexSearcher对象去索引库中查询编号对应的Document对象
7) 将Document对象中的所有属性取出,再封装回JavaBean对象中去,并加入到集合中保存,以备将之用
下面就来开始第一个Lucene的案例吧
首先引入jar包,jar包可以直接去apache的官网下载
我们将以下jar包引入
首先创建一个Article对象
package cn.qblank.lucene;/** * 文章 * @author Administrator * */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; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } @Override public String toString() { return "编号:" + id + "\n标题:" + title + "\n内容:" +content; } }然后创建一个索引库,将相应的内容存入进去
public void createIndexDB() throws IOException { //1.创建文章对象 Article article = new Article(2, "中国好室友", "中国好室友,没错,正是在下"); //2.创建document对象 Document document = new Document(); //3.将Aracle中的属性词绑定到document对象中 /* * 参数一:document中的属性名叫xid,article对象中的属性名是id,一般docuemnt属性名是在实体类的属性名前面加个x * 参数二:document对象中属性名的值,与article对象中相同 * 参数三:是否将(xid)属性值存入由原始记录表中的转存入词汇表中 * Store.YES表示会存入词汇表 * Store.No表示不会存入词汇表 * 参数四: 是否将(xid)属性值进行分词算法 * Index.ANALYZED表示该属性值会进行词汇拆分 * Index.NOT_ANALYZED表示不进行拆分(提倡非id值都进行拆分) */ document.add(new Field("xid", article.getId().toString(), Store.YES,Index.NOT_ANALYZED)); document.add(new Field("xtitle", article.getTitle(), Store.YES,Index.ANALYZED)); document.add(new Field("xcontent", article.getContent(), Store.YES,Index.ANALYZED)); //最多将文本拆分出多少个词汇,LIMITED表示1w个,即只取前1w个词汇,如果不足1w个词汇,以实际为准 MaxFieldLength maxFieldlength = MaxFieldLength.LIMITED; //Lucene索引库最终存入硬盘中的目录,例如:F:/LuceneDB FSDirectory directory = FSDirectory.open(new File("F:/LuceneDB")); //采用的分词策略 Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30); //4.创建IndexWriter对象 IndexWriter indexWriter = new IndexWriter(directory, analyzer, maxFieldlength); //将document写入Lucene索引库 indexWriter.addDocument(document); //5.关闭IndexWriter indexWriter.close();}这时候,就会在F:/Lucene的目录下创建相应的文件,如果没有这个文件夹,将会自动创建
这样,一个Lucene索引库就创建好了,接下来我们就来查询一下
public static void findIndexDB() throws Exception{ //准备输入的值 String keywords = "好"; //创建Article对象的集合 ArrayList运行结果如下:arrayList = new ArrayList (); //Lucene索引库的目录 FSDirectory directory = FSDirectory.open(new File("F:/LuceneDB")); //采用的分词策略 Version version = Version.LUCENE_30; Analyzer analyzer = new StandardAnalyzer(version); //1.创建IndexSearcher自符流对象 IndexSearcher indexSearcher = new IndexSearcher(directory); //2.创建查询解析器 /* * 参数一: 使用分词器的版本 * 参数二: 对document的属性进行搜索 */ QueryParser queryParser = new QueryParser(version,"xcontent", analyzer); //3.创建Query对象封装查询的关键字 Query query = queryParser.parse(keywords); //根据关键字去索引里面搜索 /* * 参数一: 表示关键字查询对象,其他QueryParser表示查询器 * 参数二: MAX_RECORD表示如果根据关键字搜索出来的字段较多,只取前MAX_RECORD个内容,不足MAX_RECORD个的话,以实际为准 */ int MAX_RECORD = 100; //使用indexSearcher查询前MAX_RECORD调记录 TopDocs topDocs = indexSearcher.search(query, MAX_RECORD); //4.迭代出词汇表中符合条件的编号 for (int i = 0; i < topDocs.scoreDocs.length; i++) { //取出封装编号和分数的ScoreDoc对象 ScoreDoc scoreDoc = topDocs.scoreDocs[i]; //取出每一个编号 int no = scoreDoc.doc; //5.根据编号去原始记录表中查询对应的document对象 Document document = indexSearcher.doc(no); //获取document的属性值 String xid = document.get("xid"); String xtitle = document.get("xtitle"); String xcontent = document.get("xcontent"); //6.封装到对象中 Article article = new Article(Integer.parseInt(xid), xtitle, xcontent); //添加到集合中 arrayList.add(article); } //遍历出来 for (Article article : arrayList) { System.out.println("---------"); System.out.println(article); } indexSearcher.close();}