IndexSearcher indexSearcher = new IndexSearcher(LuceneUtils.getDirectory()); // 指定所用的索引库
这句会引发线程安全问题,在全剧终 IndexSearcher只能有一个对象才可以,所以在ArticleDocumentUtils中保存一个 并且引用它。
indexSearcher为了提高效率,也是在内存中有缓存的所以需要commit才能放入索引文件数据库中 数据库优化
每次添加数据在索引文件夹下有很多小文件,为了合并小文件提高效率 //优化,合并多个小文件为一个打文件
LuceneUtils.getIndexWriter.optimize(); //配置当小文件的数量达到多少个后就自动合并为一个大文件,最小2,默认10
LucenenUtils.getIndexWriter().setMergeFactor(3);
当增加数据的时候自动触发。

Lucene.java

 package cn.itcast._util;

 import java.io.File;
import java.io.IOException; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.util.Version; public class LuceneUtils { private static Directory directory; // 索引库目录
private static Analyzer analyzer; // 分词器 private static IndexWriter indexWriter; static {
try {
// 这里应是读取配置文件得到的索引库目录
directory = FSDirectory.open(new File("./indexDir"));
analyzer = new StandardAnalyzer(Version.LUCENE_30);
} catch (IOException e) {
throw new RuntimeException(e);
}
} /**
* 获取全局唯一的IndexWriter对象
*
* @return
*/
public static IndexWriter getIndexWriter() {
// 在第一次使用IndexWriter是进行初始化
if (indexWriter == null) {
synchronized (LuceneUtils.class) { // 注意线程安全问题
if (indexWriter == null) {
try {
indexWriter = new IndexWriter(directory, analyzer, MaxFieldLength.LIMITED);
System.out.println("=== 已经初始化 IndexWriter ===");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
} // 指定一段代码,会在JVM退出之前执行。
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
indexWriter.close();
System.out.println("=== 已经关闭 IndexWriter ===");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
});
} return indexWriter;
} public static Directory getDirectory() {
return directory;
} public static Analyzer getAnalyzer() {
return analyzer;
} }

ArticleDocumentUtils.java

 package cn.itcast._util;

 import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.util.NumericUtils; import cn.itcast._domain.Article; public class ArticleDocumentUtils { /**
* 把Article转为Document
*
* @param article
* @return
*/
public static Document articleToDocument(Article article) {
Document doc = new Document(); String idStr = NumericUtils.intToPrefixCoded(article.getId()); // 一定要使用Lucene的工具类把数字转为字符串! doc.add(new Field("id", idStr, Store.YES, Index.NOT_ANALYZED)); // 注意:唯一标示符一般选择Index.NOT_ANALYZED
doc.add(new Field("title", article.getTitle(), Store.YES, Index.ANALYZED));
doc.add(new Field("content", article.getContent(), Store.YES, Index.ANALYZED)); return doc;
} /**
* 把Document转为Article
*
* @param doc
* @return
*/
public static Article documentToArticle(Document doc) {
Article article = new Article(); Integer id = NumericUtils.prefixCodedToInt(doc.get("id")); // 一定要使用Lucene的工具类把字符串转为数字! article.setId(id);
article.setTitle(doc.get("title"));
article.setContent(doc.get("content")); return article;
} }

QueryResult.java

 package cn.itcast._domain;

 import java.util.List;

 public class QueryResult {
private List list; // 一段数据列表
private int count; // 总记录数 public QueryResult(List list, int count) {
this.list = list;
this.count = count;
} public List getList() {
return list;
} public void setList(List list) {
this.list = list;
} public int getCount() {
return count;
} public void setCount(int count) {
this.count = count;
} }

ArticleIndexDao.java

 package cn.itcast.b_indexdao;

 import java.io.IOException;
import java.util.ArrayList;
import java.util.List; import org.apache.lucene.document.Document;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.util.NumericUtils;
import org.apache.lucene.util.Version; import cn.itcast._domain.Article;
import cn.itcast._domain.QueryResult;
import cn.itcast._util.ArticleDocumentUtils;
import cn.itcast._util.LuceneUtils; public class ArticleIndexDao { /**
* 保存到索引库(建立索引)
*
* @param article
*/
public void save(Article article) {
// 1,把Article转为Document
Document doc = ArticleDocumentUtils.articleToDocument(article); // 2,添加到索引库中
try {
LuceneUtils.getIndexWriter().addDocument(doc); // 添加
LuceneUtils.getIndexWriter().commit(); // 提交更改
} catch (Exception e) {
throw new RuntimeException(e);
}
} /**
* 删除索引
*
* Term :某字段中出现的某一个关键词(在索引库的目录中)
*
* @param id
*/
public void delete(Integer id) {
try {
String idStr = NumericUtils.intToPrefixCoded(id); // 一定要使用Lucene的工具类把数字转为字符串!
Term term = new Term("id", idStr); LuceneUtils.getIndexWriter().deleteDocuments(term); // 删除所有含有这个Term的Document
LuceneUtils.getIndexWriter().commit(); // 提交更改
} catch (Exception e) {
throw new RuntimeException(e);
}
} /**
* 更新索引
*
* @param article
*/
public void update(Article article) {
try {
Term term = new Term("id", NumericUtils.intToPrefixCoded(article.getId())); // 一定要使用Lucene的工具类把数字转为字符串!
Document doc = ArticleDocumentUtils.articleToDocument(article); LuceneUtils.getIndexWriter().updateDocument(term, doc); // 更新就是先删除再添加
LuceneUtils.getIndexWriter().commit(); // 提交更改 // indexWriter.deleteDocuments(term);
// indexWriter.addDocument(doc);
} catch (Exception e) {
throw new RuntimeException(e);
}
} /**
* * 搜索 用于分页的
*
* @param queryString
* 查询条件
* @param first
* 从结果列表的哪个索引开始获取数据
* @param max
* 最多获取多少条数据(如果没有这么多,就把剩余的都返回)
*
* @return 一段数据列表 + 符合条件的总记录数
*/
public QueryResult search(String queryString, int first, int max) {
IndexSearcher indexSearcher = null;
try {
// 1,把查询字符串转为Query对象(在title与content中查询)
QueryParser queryParser = new MultiFieldQueryParser(Version.LUCENE_30, new String[] { "title", "content" }, LuceneUtils.getAnalyzer());
Query query = queryParser.parse(queryString); // 2,执行查询,得到中间结果
indexSearcher = new IndexSearcher(LuceneUtils.getDirectory());
TopDocs topDocs = indexSearcher.search(query, first + max); // 最多返回前n条数据,这里要计算好,要返回足够数量的数据
int count = topDocs.totalHits; // 符合条件的总记录数 // 3,处理数据
List<Article> list = new ArrayList<Article>();
int endIndex = Math.min(first + max, topDocs.scoreDocs.length); // 计算结束的边界 for (int i = first; i < endIndex; i++) { // 应只取一段数据
// 根据内部编号获取真正的Document数据
int docId = topDocs.scoreDocs[i].doc;
Document doc = indexSearcher.doc(docId);
// 把Document转换为Article
Article article = ArticleDocumentUtils.documentToArticle(doc);
list.add(article);
} // 4,封装结果并返回
return new QueryResult(list, count); } catch (Exception e) {
throw new RuntimeException(e);
} finally {
// 关闭IndexSearcher
if (indexSearcher != null) {
try {
indexSearcher.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}

不分页的查询

LuceneUtils.getIndexWriter()
     public List<Article> searchArticle(String condition) {
// 执行搜索
List<Article> list = new ArrayList<Article>();
IndexSearcher indexSearcher = null;
try {
// 1,把查询字符串转为Query对象(默认只从title中查询)
QueryParser queryParser = new MultiFieldQueryParser(
Version.LUCENE_30, new String[] { "title", "content" },
LuceneUtils.getAnalyzer());
Query query = queryParser.parse(condition); // 2,执行查询,得到中间结果
//indexSearcher = new IndexSearcher(LuceneUtils.getDirectory()); // 指定所用的索引库,会引发线程安全问题
         indexSearcher=LuceneUtils.getIndexWriter();
TopDocs topDocs = indexSearcher.search(query, 1000); // 最多返回前n条结果
int count = topDocs.totalHits;
System.out.println("scoreDocs.length"+topDocs.scoreDocs.length); //一样
System.out.println("count"+count); //一样
ScoreDoc[] scoreDocs = topDocs.scoreDocs; // 3,处理结果
for (int i = 0; i < scoreDocs.length; i++) {
ScoreDoc scoreDoc = scoreDocs[i];
float score = scoreDoc.score; // 相关度得分
int docId = scoreDoc.doc; // Document的内部编号 // 根据编号拿到Document数据
Document document = indexSearcher.doc(docId); // 把Document转为Article
Article article=ArticleDocumentUtils.documentToArticle(document); list.add(article);
}
} catch (Exception e) {
throw new RuntimeException();
} finally {
try {
if (null != indexSearcher)
indexSearcher.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return list;
}

ArticleIndexDaoTest.java

 package cn.itcast.b_indexdao;

 import java.util.List;

 import org.junit.Test;

 import cn.itcast._domain.Article;
import cn.itcast._domain.QueryResult; public class ArticleIndexDaoTest { private ArticleIndexDao indexDao = new ArticleIndexDao(); @Test
public void testSave() {
// 准备数据
Article article = new Article();
article.setId(1);
article.setTitle("准备Lucene的开发环境");
article.setContent("如果信息检索系统在用户发出了检索请求后再去互联网上找答案,根本无法在有限的时间内返回结果。"); // 放到索引库中
indexDao.save(article);
} @Test
public void testSave_25() {
for (int i = 1; i <= 25; i++) {
// 准备数据
Article article = new Article();
article.setId(i);
article.setTitle("准备Lucene的开发环境");
article.setContent("如果信息检索系统在用户发出了检索请求后再去互联网上找答案,根本无法在有限的时间内返回结果。"); // 放到索引库中
indexDao.save(article);
}
} @Test
public void testDelete() {
indexDao.delete(1);
} @Test
public void testUpdate() {
// 准备数据
Article article = new Article();
article.setId(1);
article.setTitle("准备Lucene的开发环境");
article.setContent("这是更新后的内容"); // 更新到索引库中
indexDao.update(article);
}
//用于分页的
@Test
public void testSearch() {
// 准备查询条件
String queryString = "lucene";
// String queryString = "hibernate"; // 执行搜索
// QueryResult qr = indexDao.search(queryString, 0, 10000); // QueryResult qr = indexDao.search(queryString, 0, 10); // 第1页,每页10条
// QueryResult qr = indexDao.search(queryString, 10, 10); // 第2页,每页10条
QueryResult qr = indexDao.search(queryString, 20, 10); // 第3页,每页10条 // 显示结果
System.out.println("总结果数:" + qr.getCount());
for (Article a : (List<Article>) qr.getList()) {
System.out.println("------------------------------");
System.out.println("id = " + a.getId());
System.out.println("title = " + a.getTitle());
System.out.println("content = " + a.getContent());
}
} }

不分页查询测试

 @Test
public void testSearchArticle() {
// 准备查询条件
String queryString = "lucene的";
// String queryString = "hibernate"; // 执行搜索
List<Article> list =dao.searchArticle(queryString); // 显示结果
System.out.println("总结果数:" + list.size());
for (Article a : list) {
System.out.println("------------------------------");
System.out.println("id = " + a.getId());
System.out.println("title = " + a.getTitle());
System.out.println("content = " + a.getContent());
}
}

lucene 建立CRUD操作的更多相关文章

  1. lucene的CRUD操作Document(四)

    IndexWriter writer = new IndexWriter(Directory, IndexWriterConfig); 增加文档:writer.addDocument(); 读取文档: ...

  2. ElasticSearch基础+文档CRUD操作

    本篇博客是上一篇的延续,主要用来将年前学习ES的知识点做一个回顾,方便日后进行复习和汇总!因为近期项目中使用ES出现了点小问题,因此在这里做一个详细的汇总! [01]全文检索和Lucene (1)全文 ...

  3. 【Java EE 学习 44】【Hibernate学习第一天】【Hibernate对单表的CRUD操作】

    一.Hibernate简介 1.hibernate是对jdbc的二次开发 2.jdbc没有缓存机制,但是hibernate有. 3.hibernate的有点和缺点 (1)优点:有缓存,而且是二级缓存: ...

  4. Entity Framework 程序设计入门二 对数据进行CRUD操作和查询

    前一篇文章介绍了应用LLBL Gen生成Entity Framework所需要的类型定义,用一行代码完成数据资料的读取, <LLBL Gen + Entity Framework 程序设计入门& ...

  5. 10月16日下午MySQL数据库CRUD操作(增加、删除、修改、查询)

    1.MySQL注释语法--,# 2.2.后缀是.sql的文件是数据库查询文件. 3.保存查询. 关闭查询时会弹出提示是否保存,保存的是这段文字,不是表格(只要是执行成功了表格已经建立了).保存以后下次 ...

  6. 一步步学Mybatis-实现单表情况下的CRUD操作 (3)

    今天这一章要紧接上一讲中的东西,本章中创建基于单表操作的CRUD与GetList操作,此示例中以Visitor表为范例,为了创建一点测试数据我们先弄个Add方法吧 继续在上次的IVisitorOper ...

  7. Java实战之02Hibernate-01简介、常用接口、CRUD操作

    一.Hibernate简介 1.Hibernate在开发中所处的位置 2.ORM映射 Object :面向对象领域的 Relational:关系数据库领域的 Mapping:映射 Object: Re ...

  8. DevExpress ASP.NET 使用经验谈(5)-通过ASPxGridView实现CRUD操作

    这节,我们将通过使用DevExpress的ASPxGridView控件,实现对数据的CRUD操作. 首先,我们在解决方案中,添加一个网站: 图一 添加新网站 图二 添加DevExpress.Data. ...

  9. 【ASP.NET Web API教程】2.1 创建支持CRUD操作的Web API

    原文 [ASP.NET Web API教程]2.1 创建支持CRUD操作的Web API 2.1 Creating a Web API that Supports CRUD Operations2.1 ...

随机推荐

  1. Android如何获取屏幕的分辨

    在实际的项目中,我们经常要得到当前屏幕的分辨率,进行机型适配,得到分辨率其实很简单,主要有两种方法. 方法一: Display mDisplay = getWindowManager().getDef ...

  2. 探究Activity(1)--Activity的基本用法

    一.Activity是什么 Activity(活动)是最容易吸引用户的地方,它是一种可以包含用户界面的组件,主要用于和用户进行交互.一个应用程序中应该包括零个或多个Activity. 二.Activi ...

  3. uva1632 (区间DP)

    题意:有n个宝藏,在x轴上,每个宝藏在某个时间会消失,问最少吃完所有宝藏的时间是多少,否则输出no solution 分析:区间DP,f[i][j][01]代表i到j区间内的全部吃完,停留在左/右端, ...

  4. Redis源码解析之ziplist

    Ziplist是用字符串来实现的双向链表,对于容量较小的键值对,为其创建一个结构复杂的哈希表太浪费内存,所以redis 创建了ziplist来存放这些键值对,这可以减少存放节点指针的空间,因此它被用来 ...

  5. 用asyncio的异步网络连接来获取sina、sohu和163的网站首页

    代码如下: import asyncio async def wget(host): print('wget %s...' % host) connect = asyncio.open_connect ...

  6. 使用idea搭建Spring boot开发初始环境

    准备工作 将以下代码加入idea的live template,命名为springbootStartup <parent> <groupId>org.springframewor ...

  7. http-server 超轻量级web服务器

    有的时候做前端,想要运行一些代码,但是又没有必要使用tomcat或者Apache http server,这个时候一个轻量级的简单的http server就可以搞定了. Http-server是基于n ...

  8. node.js+mysql增删查改

    数据库和表: -- -- 数据库: `test` -- -- -------------------------------------------------------- -- -- 表的结构 ` ...

  9. [Git] 给git命令起别名

    转载自:http://blog.csdn.net/qinjienj/article/details/7479886 程序员都是"懒惰"的,哪怕是执行一个命令的时候少敲了一个字母也感 ...

  10. [Android Memory] Linux下malloc函数和OOM Killer

    http://www.linuxidc.com/Linux/2010-09/28364.htm Linux下malloc函数主要用来在用户空间从heap申请内存,申请成功返回指向所分配内存的指针,申请 ...