Lucene基础(四)-- 结合数据库使用
需求
很多时候我们在用数据库的需要使用模糊查询,我们一般会使用like语句来做,然而这样的做的效率不是很多(很抱歉我们亲自去测,很多都这么说的),那么使用Lucene来检索的话,效率会高很多。
lucene结合数据库步骤
- 写一段传统的JDBC程序,将每条的用户信息从数据库读取出来
- 针对每条用户记录,建立一个lucene document
Document doc = new Document();
并根据你的需要,将用户信息的各个字段对应luncene document中的field 进行添加,如:
doc.add(new Field(“NAME”,”USERNAME”,Field.Store.YES,Field.Index.UN_TOKENIZED));
然后将该条doc加入到索引中, 如: luceneWriter.addDocument(doc);
这样就建立了lucene的索引库 - 编写对索引库的搜索程序(看lucene文档),通过对lucene的索引库的查找,你可以快速找到对应记录的ID
- 通过ID到数据库中查找相关记录
注意
在索引的过程中,可以使用增量的方式建立索引,这样对已经索引的记录不在建立索引。实现思路:保存上次(lasttime)的新增时候的id,在建立索引的时候,值查询这个id之后的记录进行索引,更新这个记录下来的id,在数据库数据修改时候,针对这个数据制作索引的修改
操作实例
package lucene_demo05;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
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.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;
/**
*
* Lucene与数据库结合使用
*
* @author YipFun
*/
public class LuceneDemo05 {
private static final String driverClassName="com.mysql.jdbc.Driver";
private static final String url="jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8";
private static final String username="****";
private static final String password="****";
private static final Version version = Version.LUCENE_4_9;
private Directory directory = null;
private DirectoryReader ireader = null;
private IndexWriter iwriter = null;
private IKAnalyzer analyzer;
private Connection conn;
public LuceneDemo05() {
directory = new RAMDirectory();
}
public IndexSearcher getSearcher(){
try {
if(ireader==null) {
ireader = DirectoryReader.open(directory);
} else {
DirectoryReader tr = DirectoryReader.openIfChanged(ireader) ;
if(tr!=null) {
ireader.close();
ireader = tr;
}
}
return new IndexSearcher(ireader);
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public Connection getConnection(){
if(this.conn == null){
try {
Class.forName(driverClassName);
conn = DriverManager.getConnection(url, username, password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
return conn;
}
private IKAnalyzer getAnalyzer(){
if(analyzer == null){
return new IKAnalyzer();
}else{
return analyzer;
}
}
public void createIndex(){
Connection conn = getConnection();
ResultSet rs = null;
PreparedStatement pstmt = null;
if(conn == null){
System.out.println("get the connection error...");
return ;
}
String sql = "select * from t_user";
try {
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
IndexWriterConfig iwConfig = new IndexWriterConfig(version, getAnalyzer());
iwConfig.setOpenMode(OpenMode.CREATE_OR_APPEND);
iwriter = new IndexWriter(directory,iwConfig);
while(rs.next()){
int id = rs.getInt(1);
String name = rs.getString(2);
String psd = rs.getString(3);
Document doc = new Document();
doc.add(new TextField("id", id+"",Field.Store.YES));
doc.add(new TextField("name", name+"",Field.Store.YES));
doc.add(new TextField("psd", psd+"",Field.Store.YES));
iwriter.addDocument(doc);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
if(iwriter != null)
iwriter.close();
rs.close();
pstmt.close();
if(!conn.isClosed()){
conn.close();
}
} catch (IOException e) {
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void searchByTerm(String field,String keyword,int num) throws InvalidTokenOffsetsException{
IndexSearcher isearcher = getSearcher();
Analyzer analyzer = getAnalyzer();
//使用QueryParser查询分析器构造Query对象
QueryParser qp = new QueryParser(version,field,analyzer);
//这句所起效果?
qp.setDefaultOperator(QueryParser.OR_OPERATOR);
try {
Query query = qp.parse(keyword);
ScoreDoc[] hits;
//注意searcher的几个方法
hits = isearcher.search(query, null, num).scoreDocs;
System.out.println("the ids is =");
for (int i = 0; i < hits.length; i++) {
Document doc = isearcher.doc(hits[i].doc);
System.out.print(doc.get("id")+" ");
}
} catch (IOException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InvalidTokenOffsetsException {
LuceneDemo05 ld = new LuceneDemo05();
ld.createIndex();
ld.searchByTerm("name", "Bruce", 100);
}
}
索引之后就可以拿到需要id,这个时候按id查询数据库的记录,就快多了。
思考
这是对单表的数据进行索引,当我们的业务复杂的是,需要的数据通常是多个表联合查询的结果,我们的索引是如何建立?
- 使用视图,对多表建立视图,在视图上面创建索引?
- 还是单表索引,只是把联合查询化解,在lucene的索引中使用多次查询,找到目标,在数据库查询?
和数据使用的时候 ,索引到底是和数据库数据相关联的,还是和结果集相关联的?
写测试程序发现,应该是索引在数据结果集上面的。
测试如下:
t_user 表
t_user_teacher 表
t_teacher 表
package lucene_demo05;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
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.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;
/**
*
* Lucene与数据库结合使用
*
* @author YipFun
*/
public class LuceneDemo06
{
private static final String driverClassName = "com.mysql.jdbc.Driver";
private static final String url = "jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8";
private static final String username = "****";
private static final String password = "****";
private static final Version version = Version.LUCENE_4_9;
private Directory directory = null;
private DirectoryReader ireader = null;
private IndexWriter iwriter = null;
private IKAnalyzer analyzer;
private Connection conn;
public LuceneDemo06()
{
directory = new RAMDirectory();
}
public IndexSearcher getSearcher()
{
try
{
if (ireader == null)
{
ireader = DirectoryReader.open(directory);
} else
{
DirectoryReader tr = DirectoryReader.openIfChanged(ireader);
if (tr != null)
{
ireader.close();
ireader = tr;
}
}
return new IndexSearcher(ireader);
} catch (CorruptIndexException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
return null;
}
public Connection getConnection()
{
if (this.conn == null)
{
try
{
Class.forName(driverClassName);
conn = DriverManager.getConnection(url, username, password);
} catch (ClassNotFoundException e)
{
e.printStackTrace();
} catch (SQLException e)
{
e.printStackTrace();
}
}
return conn;
}
private IKAnalyzer getAnalyzer()
{
if (analyzer == null)
{
return new IKAnalyzer();
} else
{
return analyzer;
}
}
public void createIndex()
{
Connection conn = getConnection();
ResultSet rs = null;
PreparedStatement pstmt = null;
if (conn == null)
{
System.out.println("get the connection error...");
return;
}
String sql = "select " + "u.id as uid," + "u.name as uname," + "u.psd as upsd," + "u.email as uemail," + "u.tel as utel," + "t.id as tid,"
+ "t.name as tname " + "from t_user u , t_user_teacher ut ,t_teacher t " + "where u.id=ut.u_id and ut.t_id= t.id ";
try
{
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
IndexWriterConfig iwConfig = new IndexWriterConfig(version, getAnalyzer());
iwConfig.setOpenMode(OpenMode.CREATE_OR_APPEND);
iwriter = new IndexWriter(directory, iwConfig);
while (rs.next())
{
int id = rs.getInt("uid");
String name = rs.getString("uname");
String psd = rs.getString("upsd");
int tid = rs.getInt("tid");
String tname = rs.getString("tname");
Document doc = new Document();
doc.add(new TextField("uid", id + "", Field.Store.YES));
doc.add(new TextField("uname", name + "", Field.Store.YES));
doc.add(new TextField("upsd", psd + "", Field.Store.YES));
doc.add(new TextField("tid", tid + "", Field.Store.YES));
doc.add(new TextField("tname", tname + "", Field.Store.YES));
iwriter.addDocument(doc);
}
} catch (SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
} finally
{
try
{
if (iwriter != null)
iwriter.close();
rs.close();
pstmt.close();
if (!conn.isClosed())
{
conn.close();
}
} catch (IOException e)
{
e.printStackTrace();
} catch (SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void searchByTerm(String field, String keyword, int num) throws InvalidTokenOffsetsException
{
IndexSearcher isearcher = getSearcher();
Analyzer analyzer = getAnalyzer();
// 使用QueryParser查询分析器构造Query对象
QueryParser qp = new QueryParser(version, field, analyzer);
// 这句所起效果?
qp.setDefaultOperator(QueryParser.OR_OPERATOR);
try
{
Query query = qp.parse(keyword);
ScoreDoc[] hits;
// 注意searcher的几个方法
hits = isearcher.search(query, null, num).scoreDocs;
System.out.println("the ids is =");
for (int i = 0; i < hits.length; i++)
{
Document doc = isearcher.doc(hits[i].doc);
System.out.print(doc.get("uid") + " ");
}
} catch (IOException e)
{
e.printStackTrace();
} catch (ParseException e)
{
e.printStackTrace();
}
}
public static void main(String[] args) throws InvalidTokenOffsetsException
{
LuceneDemo06 ld = new LuceneDemo06();
ld.createIndex();
ld.searchByTerm("tname", "aaa", 100);
}
}
搜索教师为aaa的学生的Id
结果:
加载扩展词典:ext.dic
加载扩展停止词典:stopword.dic
the ids is = 1 2
Lucene基础(四)-- 结合数据库使用的更多相关文章
- 小白学 Python 爬虫(5):前置准备(四)数据库基础
人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...
- Lucene基础(1)
下一篇: Lucene基础(2) 一.Lucene介绍 http://www.kailing.pub/index/columns/colid/16.html Documentation:http:// ...
- Laravel教程 四:数据库和Eloquent
Laravel教程 四:数据库和Eloquent 此文章为原创文章,未经同意,禁止转载. Eloquent Database 上一篇写了一些Laravel Blade的基本用法和给视图传递变量的几种方 ...
- Lucene基础(2)
上一篇:Lucene基础(1) 一.Lucene术语 Document, Field, Term, Query, Analyzer相信在其中大多数在之前已经理解了...对其中部分概念详细说明 Docu ...
- Android基础总结+SQlite数据库【申明:来源于网络】
Android基础总结+SQlite数据库[申明:来源于网络] 基础总结篇之一:Activity生命周期:http://blog.csdn.net/liuhe688/article/details/6 ...
- day 68 Django基础四之模板系统
Django基础四之模板系统 本节目录 一 语法 二 变量 三 过滤器 四 标签Tags 五 模板继承 六 组件 七 自定义标签和过滤器 八 静态文件相关 一 语法 模板渲染的官方文档 关 ...
- day 54 Django基础四之模板系统
Django基础四之模板系统 本节目录 一 语法 二 变量 三 过滤器 四 标签Tags 五 模板继承 六 组件 七 自定义标签和过滤器 八 静态文件相关 一 语法 模板渲染的官方文档 关于模 ...
- Django基础四之测试环境和ORM查询
Django基础四之测试环境和ORM查询 目录 Django基础四之测试环境和ORM查询 1. 搭建测试环境 1.1 测试环境搭建方法: 1.2 使用测试环境对数据库进行CURD 1.3 返回Quer ...
- django-rest-framework 基础四 过滤、排序、分页、异常处理
django-rest-framework 基础四 过滤.排序.分页.异常处理 目录 django-rest-framework 基础四 过滤.排序.分页.异常处理 1. 过滤 1.1 内置过滤类 1 ...
- Python全栈开发【基础四】
Python全栈开发[基础四] 本节内容: 匿名函数(lambda) 函数式编程(map,filter,reduce) 文件处理 迭代器 三元表达式 列表解析与生成器表达式 生成器 匿名函数 lamb ...
随机推荐
- Android View的绘制机制流程深入详解(三)
本系列文章主要着重深入介绍Android View的绘制机制及流程,第三篇主要介绍并分析视图状态以及重绘流程,首先剖析了 视图的几种状态,然后在深入分析视图的重绘机制流程. 真题园网:http://w ...
- 高灵活低耦合Adapter快速开发攻略
Android开发中经常需要使用Adapter. 传统方法是自定义一个Adapter并继承AndroidSDK内的BaseAdapter, 这种方式代码量大,耦合度高,灵活性差(各种监听事件需要对Vi ...
- mapping 详解1(mapping type)
映射(mapping) 映射是定义一个文档以及其所包含的字段如何被存储和索引的方法. 例如,用映射来定义以下内容: 哪些 string 类型的 field 应当被当成当成 full-text 字段 哪 ...
- Javascript实现图片无缝滚动
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- javascript 获取下一个节点
下一个节点: nextElementSibling 上一个节点 previousElementSibling <div> <select onchange="alert(t ...
- nginx支持url的PATHINFO
fastcgi_split_path_info ^(.+?\.php)(/.*)$; set $path_info $fastcgi_path_info; fastcgi_param PATH_INF ...
- QL Server 中四种匹配符的含义
SQL中我们会见到很多的匹配符,下面解释一下 % 代表零个或者多个任意字符 _ 代表一个任意字符 [] 指定范围内的任意单个字符 [^] 不在指定范围内的任意单个字符 带有匹配符的字符串必须使用引号引 ...
- 精妙SQL语句介绍
说明:复制表(只复制结构,源表名:a 新表名:b) SQL: select * into b from a where 1<>1 说明:拷贝表(拷贝数据,源表名:a 目标表名:b) SQL ...
- 关于error: cannot connect to daemon的解决办法
执行adb devices时,如果出现以下错误: * daemon not running. starting it now on port 5037 * ADB server didn't ACK ...
- WCF编程系列(七)信道及信道工厂
WCF编程系列(七)信道及信道工厂 信道及信道栈 前面已经提及过,WCF中客户端与服务端的交互都是通过消息来进行的.消息从客户端传送到服务端会经过多个处理动作,在WCF编程模型中,这些动作是按层 ...