文档章节

在项目中使用Lucene进行全文检索

SPPan
 SPPan
发布于 2017/06/02 10:20
字数 1057
阅读 25
收藏 1

本文主要讲解在maven项目中使用Lucene进行全文检索的基本步骤。

一、首先需要引入依赖,使用的版本为4.7.2。

<!--核心包-->
<dependency>
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-core</artifactId>
    <version>4.7.2</version>
</dependency>
<!--关键字高亮-->
<dependency>
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-highlighter</artifactId>
    <version>4.7.2</version>
</dependency>
<!--分词-->
<dependency>
    <groupId>com.janeluo</groupId>
    <artifactId>ikanalyzer</artifactId>
    <version>2012_u6</version>
</dependency>

二、创建一个Javabean作为数据传输对象

public class SearcherBean {

	private String sid;
	private String title;
	private String description;
	private String content;
	private String url;
	private Date created;

	private Object data; // 保存其他信息,不是用来检索的

	public SearcherBean() {
	}

	public SearcherBean(String sid, String title, String description, String content, String url, Date created,
			Object data) {
		this.sid = sid;
		this.title = title;
		this.description = description;
		this.content = content;
		this.url = url;
		this.created = created;
		this.data = data;
	}

	public String getSid() {
		return sid;
	}

	public void setSid(String sid) {
		this.sid = sid;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public Date getCreated() {
		return created;
	}

	public void setCreated(Date created) {
		this.created = created;
	}

	public Object getData() {
		return data;
	}

	public void setData(Object data) {
		this.data = data;
	}
	
}

三、增加索引

public void addBean() {
    IndexWriter writer = null;
    try {
        //指定文件存储路径
        Directory directory = NIOFSDirectory.open(new File("c://"));
        //创建词法分析
        Analyzer analyzer = new IKAnalyzer();
        //创建IndexWriter
        IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_47, analyzer);
        writer = new IndexWriter(directory, iwc);
        //创建文档
        Document doc = createDoc(bean);
        //保存文档
        writer.addDocument(doc);
    } catch (Exception e) {
        logger.error("add bean to lucene error", e);
    } finally {
        try {
            if (writer != null) {
               writer.close();
            }
        } catch (IOException e) {
            logger.error("close failed", e);
        }
    }
}
/**
* 创建Doc
* @param bean
* @return
*/
private Document createDoc(SearcherBean bean) {
        Document doc = new Document();
        doc.add(new StringField("id", bean.getId(), Field.Store.YES));
        doc.add(new TextField("title", bean.getTitle(), Field.Store.YES));
        doc.add(new TextField("summary", bean.getSummary(), Field.Store.YES));
        doc.add(new TextField("content", bean.getContent(), Field.Store.YES));	
        doc.add(new StringField("authorName", bean.getAuthorName(), Field.Store.YES));
        doc.add(new IntField("views", bean.getViews(), Field.Store.YES));
        doc.add(new StringField("createdAt", DateTools.dateToString(bean.getCreateAt(), DateTools.Resolution.MILLISECOND), Field.Store.YES));
        return doc;
}

四、删除索引

@Override
public void deleteBean(String beanId) {
    IndexWriter writer = null;
    try {
        IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_47, analyzer);
        writer = new IndexWriter(directory, iwc);
        writer.deleteDocuments(new Term("id", beanId));
    } catch (IOException e) {
        logger.error("delete bean to lucene error,beanId:"+beanId,e);
    } catch (InterruptedException e) {
        logger.error("delete bean to lucene error,beanId:"+beanId,e);
    } finally {
        try {
            if(writer!=null) {
                writer.close();
            }
        } catch (IOException e) {
            logger.error("close failed", e);
        }
    }
}
    
/**
 * 删除所有
 */
@Override
public void deleteAllBean() {
	IndexWriter writer = null;
	try {
		IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_47, analyzer);
		writer = new IndexWriter(directory, iwc);
		writer.deleteAll();
	} catch (IOException e) {
		logger.error("delete allBean to lucene error",e);
	} catch (InterruptedException e) {
		logger.error("delete allBean to lucene error",e);
	} finally {
		try {
			if(writer!=null) {
				writer.close();
			}
		} catch (IOException e) {
			logger.error("close failed", e);
		}
	}
}

五、检索

/**
 *  转换为SearchBean
 * @param searcher
 * @param topDocs
 * @return
 * @throws IOException
 */
private List getSearcherBeans(Query query, IndexSearcher searcher, TopDocs topDocs) throws IOException {
    List searcherBeans = new ArrayList();
    for (ScoreDoc item : topDocs.scoreDocs) {
        Document doc = searcher.doc(item.doc);
        SearcherBean searcherBean = new SearcherBean();
        searcherBean.setId(doc.get("id"));
        
        searcherBean.setTitle(setHighlighter(query, doc, "title"));
        searcherBean.setSummary(setHighlighter(query, doc, "summary"));
        searcherBean.setContent(setHighlighter(query, doc, "content"));
        
        searcherBean.setViews(Integer.parseInt(doc.get("views")));
        searcherBean.setAuthorName(doc.get("authorName"));
        
        try {
			searcherBean.setCreateAt(DateTools.stringToDate(doc.get("createdAt")));
		} catch (java.text.ParseException e) {
			e.printStackTrace();
		}
        searcherBeans.add(searcherBean);
    }
    return searcherBeans;
}
/**
 * 获取Query 对象
 * @param keyword
 * @param module
 * @return
 */
private Query getQuery(String keyword) {
    try {
        QueryParser queryParser1 = new QueryParser(Version.LUCENE_47, "content", analyzer);
        Query termQuery1 = queryParser1.parse(keyword);
        
        QueryParser queryParser2 = new QueryParser(Version.LUCENE_47, "title", analyzer);
        Query termQuery2 = queryParser2.parse(keyword);
        
        QueryParser queryParser3 = new QueryParser(Version.LUCENE_47, "summary", analyzer);
        Query termQuery3 = queryParser3.parse(keyword);
        
        BooleanQuery booleanClauses = new BooleanQuery();
        booleanClauses.add(new BooleanClause(termQuery1, BooleanClause.Occur.SHOULD));
        booleanClauses.add(new BooleanClause(termQuery2, BooleanClause.Occur.SHOULD));
        booleanClauses.add(new BooleanClause(termQuery3, BooleanClause.Occur.SHOULD));
        
        booleanClauses.setMinimumNumberShouldMatch(1);
        return booleanClauses;
    } catch (ParseException e) {
        e.printStackTrace();
    }
    return null;
}
/**
 * 通过关键字搜索分页
 * 
 * @param keyword 关键字
 */
@Override
public Page search(String keyword) {
    try {
        IndexReader aIndexReader = DirectoryReader.open(directory);
        IndexSearcher searcher = null;
        searcher = new IndexSearcher(aIndexReader);
        Query query = getQuery(keyword);
        TopDocs topDocs = searcher.search(query, 50);
        List searcherBeans = getSearcherBeans(query, searcher, topDocs);
        Page searcherBeanPage = new Page<>(searcherBeans, 1, 10, 100, 1000);
        return searcherBeanPage;
    } catch (Exception e) {
    }
    return null;
}
/**
 * 分页检索
 * @param pageNum 当前页
 * 
 * @param pageSize 每页条数
 * 
 * @param queryString 关键字
 * 
 */
@Override
public Page search(int pageNum, int pageSize, String queryString) {
    IndexReader aIndexReader = null;
    try {
        aIndexReader = DirectoryReader.open(directory);
        IndexSearcher searcher = null;
        searcher = new IndexSearcher(aIndexReader);
        Query query = getQuery(queryString);
        ScoreDoc lastScoreDoc = getLastScoreDoc(pageNum, pageSize, query, searcher);
        TopDocs topDocs = searcher.searchAfter(lastScoreDoc, query, pageSize);
        List searcherBeans = getSearcherBeans(query, searcher, topDocs);
        int totalRow = searchTotalRecord(searcher, query);
        int totalPages;
        if ((totalRow % pageSize) == 0) {
            totalPages = totalRow / pageSize;
        } else {
            totalPages = totalRow / pageSize + 1;
        }
        Page searcherBeanPage = new Page<>(searcherBeans, pageNum, pageSize, totalPages, totalRow);
        return searcherBeanPage;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}
/**
 * 根据页码和分页大小获取上一次最后一个ScoreDoc
 *
 * @param pageIndex
 * @param pageSize
 * @param query
 * @param indexSearcher
 * @return
 * @throws IOException
 */
private ScoreDoc getLastScoreDoc(int pageIndex, int pageSize, Query query, IndexSearcher indexSearcher) throws IOException {
    if (pageIndex == 1) return null;//如果是第一页返回空
    int num = pageSize * (pageIndex - 1);//获取上一页的数量
    TopDocs tds = indexSearcher.search(query, num);
    return tds.scoreDocs[num - 1];
}
/**
 * @param query
 * @return
 * @throws IOException
 * @Title: searchTotalRecord
 * @Description: 获取符合条件的总记录数
 */
public int searchTotalRecord(IndexSearcher searcher, Query query) throws IOException {
    TopDocs topDocs = searcher.search(query, Integer.MAX_VALUE);
    if (topDocs == null || topDocs.scoreDocs == null || topDocs.scoreDocs.length == 0) {
        return 0;
    }
    ScoreDoc[] docs = topDocs.scoreDocs;
    return docs.length;
}

设置关键字高亮

/**
 * 高亮设置
 * @param query
 * @param doc
 * @param field
 * @return
 */
private String setHighlighter(Query query,Document doc,String field){
    try {
        SimpleHTMLFormatter simpleHtmlFormatter = new SimpleHTMLFormatter("", "");
        Highlighter highlighter = new Highlighter(simpleHtmlFormatter,new QueryScorer(query));
        String fieldValue = doc.get(field);
        String highlighterStr = highlighter.getBestFragment(analyzer,field,fieldValue);
        return highlighterStr == null ? fieldValue:highlighterStr;
    } catch (Exception e) {
    	e.printStackTrace();
    }
    return null;
}

© 著作权归作者所有

共有 人打赏支持
SPPan
粉丝 10
博文 29
码字总数 15103
作品 0
成都
程序员
Spring Boot 中使用 Java API 调用 lucene

Lucene是apache软件基金会4 jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引...

PengLei
2017/11/08
0
0
高手问答第 179 期 —— 全文检索技术分享:从 Lucene 到 Elasticsearch

OSCHINA 本期高手问答(11 月 29 日 - 12 月 5 日)我们请来了@napoay 姚攀为大家解答关于全文检索技术的问题。 姚攀,中国科学院大学硕士,热爱撰写技术博客、翻译文档。研究生期间因选修信工...

局长
2017/11/28
4.6K
71
Hibernate Search 5.0.0 RC1 发布

Hibernate Search 5.0.0 RC1 发布,此版本默认情况下使用 Lucene 的 NumericField 数值字段(s)。更多更新内容请看发行说明。 Hibernate Search的作用是对数据库中的数据进行检索的。它是hib...

oschina
2014/12/10
1K
12
Hibernate Search 4.1.0.Beta1 发布

Hibernate Search version 4.1.0.Beta1 发布了,该版本最大的改变就是:HSEARCH-1034 ,可通过可编程 API 使用 Infinispan Query。另外还包括 MassIndexer 改进,性能提升等。 Hibernate Se...

红薯
2012/02/07
365
0
我心中的核心组件(可插拔的AOP)~第十四回 全文检索架构~终于设计了一个自己满意的Lucene架构

我架构的以lucene为技术的全文检索分为lucene检索模块,索引文件生成器和WEB检索测试三个部分组成 结构如下: lucene模块它由通过检索项和几个具体检索业务子项目组成 通过功能项目结构为: ...

mcy247
2017/12/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

go语言学习总结

一、描述 go语言是直接将源码编译成二进制机器码的语言;它支持面向对象、也支持函数式编程;支持并发很容易; 二、基本语法学习路径 https://studygolang.com/subject/2...

盼望明天
13分钟前
1
0
JSP 九大内置对象及其作用域

JSP 中一共预先定义了 9 个这样的对象,分别为:request、response、session、application、out、pagecontext、config、page、exception ,下面就简单介绍下。 1、request 对象 request 对象...

几个栗子
24分钟前
0
0
Java中的坑之方括号

Java中的坑之方括号 这一段时间,在做项目的时候,发现了一个坑,这个坑说大不大,说小不小,不知道的足够喝一壶,知道的就可以轻松解决。 问题描述 在做数据统计的时候,遇见了如下形式的数...

星汉
34分钟前
1
0
[雪峰磁针石博客]python机器学习、web开发等书籍汇总

Building Machine Learning Systems with Python Third Edition - 2018.pdf 下载地址 Get more from your data by creating practical machine learning systems with Python Key Features ......

python测试开发人工智能安全
45分钟前
1
0
文件的压缩与解压(linux)

Linux下*.tar.gz文件解压缩命令 1.压缩命令:   命令格式:tar -zcvf 压缩后文件名.tar.gz 被压缩文件名 可先切换到当前目录下。压缩文件名和被压缩文件名都可加入路径。 2.解压缩命令: ...

qimh
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部