今天 用lucene完毕了 一个简单的web应用。提取了早期编写的一个測试类。 首先简单介绍下lucene几个经常使用包;

lucene 包的组成结构:对于外部应用来说索引模块(index)和检索模块(search)是基本的外部应用入口



org.apache.Lucene.search/ 搜索入口 

org.apache.Lucene.index/ 索引入口 

org.apache.Lucene.analysis/ 语言分析器 

org.apache.Lucene.queryParser/ 查询分析器 

org.apache.Lucene.document/ 存储结构 

org.apache.Lucene.store/  底层IO/存储结构 

org.apache.Lucene.util/ 一些公用的数据结构

话不多说,直接上代码(这是早期封装的一个測试类。封装的还算比較完好,有兴趣的朋友能够在此基础上继续完好):

package com.lucene.util;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.List; import org.apache.log4j.Logger;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.LogDocMergePolicy;
import org.apache.lucene.index.LogMergePolicy;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleFragmenter;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.NumericUtils;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer; import com.message.base.search.SearchBean; /**
* lucene 4.10.1
*
* @creatTime 2014-10-28
* @author 胡慧超
*
*/
public class HhcIndexTools { private final static Logger logger = Logger.getLogger(HhcIndexTools.class);
private static String indexPath = "E://lucene//index"; public static void main(String[] args) {
try {
// createIndex();
// searchIndex("码农");
// query();
// deleteIndex(null);
forceDeleteIndex();
query();
highlighterSearch();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} /**
* 创建索引
*/
public static void createIndex() {
// 最细粒切分算法--true的话是 智能切分
Analyzer analyzer = new IKAnalyzer(false);
Document doc = null;
IndexWriter indexWriter = null;
try {
indexWriter = getIndexWriter(analyzer);
// 加入索引
doc = new Document();
doc.add(new StringField("id", "1", Store.YES));
doc.add(new TextField("title", "标题:開始", Store.YES));
doc.add(new TextField("content", "内容:我如今是个码农", Store.YES));
indexWriter.addDocument(doc);
doc = new Document();
doc.add(new StringField("id", "2", Store.YES));
doc.add(new TextField("title", "标题:结束", Store.YES));
doc.add(new TextField("content", "内容:我如今是个lucene开发project师的专家",
Store.YES));
indexWriter.addDocument(doc);
indexWriter.commit();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
logger.info("索引器发送异常");
} finally {
try {
destroyWriter(indexWriter);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} /**
* 搜索文档
*
* @param keyword
*/
@SuppressWarnings("deprecation")
public static void searchIndex(String keyword) {
IndexReader indexReader = null;
IndexSearcher indexSearcher = null;
try {
// 1.创建Directory 在硬盘上的F:/luence/index下建立索引
Directory dir = FSDirectory.open(new File(indexPath));
// 2.创建IndexReader
indexReader = IndexReader.open(dir);
// 实例化搜索器
indexSearcher = new IndexSearcher(indexReader); // 使用QueryParser查询分析器构造Query对象
QueryParser parse = new QueryParser(Version.LUCENE_4_10_1,
"content", new IKAnalyzer(false));
// 搜索包括keyword关键字的文档
Query query = parse.parse(keyword.trim()); // 使用lucene构造搜索引擎的时候,假设要针对多个域进行一次性查询
// 这样的方法的优点就是能够加权给字段的控制
// 在这四个域中检索
String[] fields = { "phoneType", "name", "category", "price" };
Query querys = new MultiFieldQueryParser(Version.LATEST, fields,
new IKAnalyzer(false)).parse(keyword.trim()); TopDocs results = indexSearcher.search(query, 1000);
// 6.依据TopDocs获取ScoreDoc对象
ScoreDoc[] score = results.scoreDocs;
if (score.length > 0) {
logger.info("查询结果数:" + score.length);
System.out.println("查询结果数:" + score.length);
for (int i = 0; i < score.length; i++) {
// 7.依据Seacher和ScoreDoc对象获取详细的Document对象
Document doc = indexSearcher.doc(score[i].doc);
// 8.依据Document对象获取须要的值
System.out.println(doc.toString());
System.out.println(doc.get("title") + "["
+ doc.get("content") + "]");
}
} else {
}
} catch (Exception e) {
// TODO: handle exception
logger.info("查询结果为空!");
} finally {
if (indexReader != null) {
try {
indexReader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} } /**
* 对搜索返回的前n条结果进行分页显示
*
* @param keyWord
* 查询关键词
* @param pageSize
* 每页显示记录数
* @param currentPage
* 当前页
* @throws ParseException
*/
@SuppressWarnings("deprecation")
public void paginationQuery(String keyWord, int pageSize, int currentPage)
throws IOException, ParseException {
String[] fields = { "title", "content" };
QueryParser queryParser = new MultiFieldQueryParser(Version.LATEST,
fields, new IKAnalyzer());
Query query = queryParser.parse(keyWord.trim()); IndexReader indexReader = IndexReader.open(FSDirectory.open(new File(
indexPath)));
IndexSearcher indexSearcher = new IndexSearcher(indexReader); // TopDocs 搜索返回的结果
TopDocs topDocs = indexSearcher.search(query, 100);// 仅仅返回前100条记录
TopDocs all = indexSearcher.search(new MatchAllDocsQuery(), 100);
// int totalCount = topDocs.totalHits; // 搜索结果总数量
ScoreDoc[] scoreDocs = topDocs.scoreDocs; // 搜索返回的结果集合 // 查询起始记录位置
int begin = pageSize * (currentPage - 1);
// 查询终止记录位置
int end = Math.min(begin + pageSize, scoreDocs.length); // 进行分页查询
for (int i = begin; i < end; i++) {
int docID = scoreDocs[i].doc;
System.out.println("docID=" + docID);
Document doc = indexSearcher.doc(docID);
String title = doc.get("title");
System.out.println("title is : " + title);
}
indexReader.close();
} @SuppressWarnings("deprecation")
public static void highlighterSearch() throws IOException, ParseException, InvalidTokenOffsetsException {
IndexReader reader = IndexReader.open(FSDirectory.open(new File(
indexPath)));
IndexSearcher searcher = new IndexSearcher(reader); // String []fields={"title","content"};
// QueryParser parser=new MultiFieldQueryParser(Version.LATEST, fields,
// new IKAnalyzer());
// Query query=parser.parse(""); Term term = new Term("content", "lucene");
TermQuery query = new TermQuery(term); TopDocs topdocs = searcher.search(query, Integer.MAX_VALUE);
ScoreDoc[] scoreDoc = topdocs.scoreDocs;
System.out.println("查询结果总数:" + topdocs.totalHits);
System.out.println("最大的评分:" + topdocs.getMaxScore()); for(int i=0;i<scoreDoc.length;i++){
int docid=scoreDoc[i].doc;
Document document=searcher.doc(docid);
System.out.println("============文件【"+(i+1)+"】=========");
System.out.println("检索关键字:"+term.toString());
String content=document.get("content"); //高亮展示 SimpleHTMLFormatter //
SimpleHTMLFormatter formatter=new SimpleHTMLFormatter("<font color='red'>", "</font>");
Highlighter highlighter=new Highlighter(formatter, new QueryScorer(query));
highlighter.setTextFragmenter(new SimpleFragmenter(content.length())); if(!"".equals(content)){
TokenStream tokenstream=new IKAnalyzer().tokenStream(content, new StringReader(content));
String highLightText = highlighter.getBestFragment(tokenstream,content);
System.out.println("高亮显示第 " + (i + 1) + " 条检索结果例如以下所看到的:");
System.out.println(highLightText);
/*End:结束关键字高亮*/
System.out.println("文件内容:"+content);
System.out.println("匹配相关度:"+scoreDoc[i].score);
}
}
} /**
* 获取indexWriter对象---获取索引器
*
* @param dir
* @param analyer
* @return
* @throws IOException
*/
private static IndexWriter getIndexWriter(Analyzer analyzer)
throws IOException {
File indexFile = new File(indexPath);
if (!indexFile.exists())
indexFile.mkdir();// 索引库不存在 则新建一个
Directory directory = FSDirectory.open(indexFile);
// Directory directory = new RAMDirectory(); //在内存中建立索引 IndexWriterConfig conf = new IndexWriterConfig(Version.LUCENE_4_10_1,
analyzer);
LogMergePolicy mergePolicy = new LogDocMergePolicy();
// 索引基本配置
// 设置segment加入文档(Document)时的合并频率
// 值较小,建立索引的速度就较慢
// 值较大,建立索引的速度就较快,>10适合批量建立索引
mergePolicy.setMergeFactor(30);
// 设置segment最大合并文档(Document)数
// 值较小有利于追加索引的速度
// 值较大,适合批量建立索引和更快的搜索
mergePolicy.setMaxMergeDocs(5000);
conf.setMaxBufferedDocs(10000);
conf.setMergePolicy(mergePolicy);
conf.setRAMBufferSizeMB(64); conf.setOpenMode(OpenMode.CREATE_OR_APPEND);
if (IndexWriter.isLocked(directory)) {// ?
IndexWriter.unlock(directory);
}
IndexWriter indexWriter = new IndexWriter(directory, conf);
return indexWriter;
} /**
* 销毁writer
*
* @param writer
* @throws IOException
*/
private static void destroyWriter(IndexWriter indexWriter)
throws IOException {
if (indexWriter != null) {
indexWriter.close();
}
} /**
* 批量删除
*
* @param list
* @throws IOException
*/
public static void deleteIndexs(List<SearchBean> list) throws IOException {
if (list == null || list.size() > 0) {
logger.debug("beans is null");
return;
}
for (SearchBean bean : list) {
deleteIndex(bean);
}
} /**
* 删除单个索引 --不会立马删除,生成.del文件
*
* @param bean
* @throws IOException
*/
private static void deleteIndex(SearchBean bean) throws IOException {
// if(bean==null){
// logger.debug("Get search bean is empty!");
// return;
// }
IndexWriter indexWriter = getIndexWriter(new IKAnalyzer());
// 參数是一个选项,能够是一个Query,也能够是一个term,term是一个精确查找的值
// 这里删除id=1的文档,还会留在”回收站“。xxx.del
indexWriter.deleteDocuments(new Term("id", "1"));
destroyWriter(indexWriter);
} /**
* 查询文档
*/
@SuppressWarnings("deprecation")
public static void query() {
// 1.创建Directory 在硬盘上的F:/luence/index下建立索引
try {
IndexReader indexReader = IndexReader.open(FSDirectory
.open(new File(indexPath)));
System.out.println("存储的文档数:" + indexReader.numDocs());
System.out.println("总存储量:" + indexReader.maxDoc());
System.out.println("被删除的文档:" + indexReader.numDeletedDocs());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} /**
* 回滚回收站
*
* @throws IOException
*/
public void recoveryIndexByIsDelete() throws IOException {
IndexWriter indexWriter = getIndexWriter(new IKAnalyzer());
indexWriter.rollback();
destroyWriter(indexWriter);
} /**
* 清空回收站 在版本号3.6之后,已经没有了unDeleteAll()方法了
*
* @throws IOException
*/
public static void forceDeleteIndex() throws IOException {
IndexWriter indexWriter = getIndexWriter(new IKAnalyzer());
indexWriter.forceMergeDeletes();
destroyWriter(indexWriter);
} /**
* 更新索引
*
* @throws IOException
*/
public void update() throws IOException {
IndexWriter indexWriter = new IndexWriter(FSDirectory.open(new File(
indexPath)), new IndexWriterConfig(Version.LATEST,
new IKAnalyzer(true))); Document document = new Document(); document.add(new Field("id", "10", Field.Store.YES,
Field.Index.NOT_ANALYZED_NO_NORMS));
document.add(new Field("email", "9481629991", Field.Store.YES,
Field.Index.NOT_ANALYZED));
document.add(new Field("name", "小米", Field.Store.YES,
Field.Index.NOT_ANALYZED_NO_NORMS));
document.add(new Field("content", "小米好", Field.Store.NO,
Field.Index.ANALYZED)); // 这里的更新,从方法上能够看出,它实际上时将旧的删除,然后加入一个新文档的进去,将匹配到term的文档删除,然后就新的document加入进去
indexWriter.updateDocument(new Term("id", "1"), document); indexWriter.close();
}
}

另外附带高亮的项目代码

	/**
* 高亮的公共方法
* @param text --查询内容
* @param query --查询query
* @param field --查询域
* @return
*/
private String highligher(String text,Query query,String field) {
try {
QueryScorer scorer = new QueryScorer(query);
Fragmenter fragmenter = new SimpleSpanFragmenter(scorer);
Formatter formatter = new SimpleHTMLFormatter("<span class='lighter'>","</span>");
Highlighter lighter = new Highlighter(formatter,scorer);
lighter.setTextFragmenter(fragmenter);
String ht = lighter.getBestFragment(LuceneContext.getInstance().getAnalyzer(),
field,text);
if(ht==null) {
if(text.length()>=200) {
text = text.substring(0, 200);
text=text+"....";
}
return text;
}
else return ht.trim();
} catch (IOException e) {
e.printStackTrace();
} catch (InvalidTokenOffsetsException e) {
e.printStackTrace();
}
return text;
}

全文检索(二)-基于lucene4.10的增删改查的更多相关文章

  1. 基于pymysql模块的增删改查

    上课笔记 重点:(熟练)多表查询创建存储过程原生sql索引原理 pymysql 封装好的客户端cursor 底层就是一个send操作commit 告诉mysql真的要完成修改操作(不然修改不会生效)e ...

  2. EF6 学习笔记(二):操练 CRUD 增删改查

    EF6学习笔记总目录 ASP.NET MVC5 及 EF6 学习笔记 - (目录整理) 接上篇: EF6 学习笔记(一):Code First 方式生成数据库及初始化数据库实际操作 本篇原文链接: I ...

  3. 基于DRF的图书增删改查练习

    功能演示 信息展示 添加功能 编辑功能 删除功能 DRF构建后台数据 本例的Model如下 from django.db import models class Publish(models.Mode ...

  4. 基于DRF的图书增删改查

    功能演示 信息展示 添加功能 编辑功能 删除功能 DRF构建后台数据 本例的Model如下 from django.db import models class Publish(models.Mode ...

  5. Python Web实战:Python+Django+MySQL实现基于Web版的增删改查

    前言 本篇使用Python Web框架Django连接和操作MySQL数据库学生信息管理系统(SMS),主要包含对学生信息增删改查功能,旨在快速入门Python Web,少走弯路.效果演示在项目实战最 ...

  6. MySQL数据库(二)-数据库的增删改查

    简介: 以下是MySQL最基本的增删改查语句.在进行“增删改查”的操作之前,先建立一个包含数据表student的数据库,新建表grade(具体操作可以见上一篇). 一."增"-添加数据 1.1 为表中 ...

  7. MVC3学习:基于ObjectContext的数据增删改查操作

    数据库里面的表格,映射为对应的实体类.实体类的编写,可以自己手动编写,也可以使用工具或插件自动生成.在MVC3里面,我们可以使用VS的POCO插件自动生成实体类.如下图: 关于POCO插件的安装与使用 ...

  8. MongoDB(二)-- Java API 实现增删改查

    一.下载jar包 http://central.maven.org/maven2/org/mongodb/mongo-java-driver/ 二.代码实现 package com.xbq.mongo ...

  9. SQL学习(二)SQL基础的增删改查

    在测试时使用数据库时,用的比较多的就是增删改查SQL了. 一.增加(insert into ...values) 用于向表中插入新记录 1.不指定列(表示:依次插入所有列的值) insert into ...

随机推荐

  1. python猜年龄游戏升级版

    猜年龄游戏升级版 要求:允许用户最多尝试3次,每尝试3次后,如果还没猜对,就问用户是否还想继续玩,如果回答Y,就继续让其猜3次,以此往复,如果回答N,就退出程序,如何猜对了,就直接退出 age = 1 ...

  2. Maven实战读书笔记(四):Maven生命周期与插件

    Maven的生命周期是对所有构建过程的抽象和统一.包含了项目的清理.初始化.编译.测试.打包.集成测试.验证.部署和站点生成等几乎所有构建步骤. Maven的生命周期是抽象的,其实际行为是由插件来完成 ...

  3. TCP socket编程记录(C语言)

    最近使用到TCP的socket编程,记录一下思路. TCP Socket 服务器编程思路 0.初始化套接字库 1.创建套接字----------2个(服务器本身需要一个套接字,客户端要返回一个套接字) ...

  4. mysql查询表中最小可用id值

    今天在看实验室的项目时,碰到的一个问题,.先把sql语句扔出来 // 这条语句在id没有1时,不能得到正确的查询结果. select min(id+1) from oslist c where not ...

  5. CSS--基础块级元素与内联元素

    在CSS中,html中的标签元素大体被分为三种不同的类型:块状元素.内联元素(又叫行内元素)和内联块状元素.在HTML和XHTML中,块级元素不能继承自行内元素(即不能嵌套在行内元素),<p&g ...

  6. 07 mongodb

    mongodb mongodb简介 简介 MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为Web应用提供可扩展的高性能数据存储解决方案.    MongoDB是一个介于关系数据 ...

  7. LeetCode(81) Search in Rotated Array II

    题目 Follow up for "Search in Rotated Sorted Array": What if duplicates are allowed? Would t ...

  8. Vijos 1308 埃及分数(迭代加深搜索)

    题意: 输入a.b, 求a/b 可以由多少个埃及分数组成. 埃及分数是形如1/a , a是自然数的分数. 如2/3 = 1/2 + 1/6, 但埃及分数中不允许有相同的 ,如不可以2/3 = 1/3 ...

  9. BZOJ2726【SDOI2012】任务安排(斜率优化Dp+二分查找)

    由题目条件显然可以得到状态 f[i][j] 表示以 i 为结尾且 i 后作为断点,共做了 j 次分组的最小代价. 因此转移变得很显然:f[i][j]=min{f[k][j-1]+(s×j+sumT[i ...

  10. java基础之switch

    switch 语句由一个控制表达式和多个case标签组成. switch 控制表达式支持的类型有byte.short.char.int.enum(Java 5).String(Java 7). swi ...