`
IrenBJ
  • 浏览: 27425 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Lucene检索数据库(入门篇),支持中文检索

阅读更多

全文分两部分:

一:Lucene简介

      Lucene版本:3.0.2

     全文检索大体分两个部分:索引创建(Indexing)和搜索索引(Search

     1. 索引过程:

        1) 有一系列被索引文件(此处所指即数据库数据)

        2) 被索引文件经过语法分析和语言处理形成一系列词(Term)

        3) 经过索引创建形成词典和反向索引表。

        4) 通过索引存储将索引写入硬盘。

    2. 搜索过程:

       a) 用户输入查询语句。

       b) 对查询语句经过语法分析和语言分析得到一系列词(Term)

       c) 通过语法分析得到一个查询树。

       d) 通过索引存储将索引读入到内存。

       e) 利用查询树搜索索引,从而得到每个词(Term)的文档链表,对文档链表进行交,差,并得到结果文档。

       f) 将搜索到的结果文档对查询的相关性进行排序。

       g) 返回查询结果给用户。

 

 

   索引过程如下:

       ◦ 创建一个IndexWriter用来写索引文件,它有几个参数,INDEX_DIR就是索引文件所存放的位置,Analyzer便是用来对文档进行词法分析和语言处理的。

       ◦ 创建一个Document代表我们要索引的文档。

       ◦ 将不同的Field加入到文档中。我们知道,一篇文档有多种信息,如题目,作者,修改时间,内容等。不同类型的信息用不同的Field来表示,在本例子中,一共有两类信息进行了索引,一个是文件路径,一个是文件内容。其中FileReaderSRC_FILE就表示要索引的源文件。

       ◦ IndexWriter调用函数addDocument将索引写到索引文件夹中。

   • 搜索过程如下:

       ◦ IndexReader将磁盘上的索引信息读入到内存,INDEX_DIR就是索引文件存放的位置。

       ◦ 创建IndexSearcher准备进行搜索。

       ◦ 创建Analyer用来对查询语句进行词法分析和语言处理。

       ◦ 创建QueryParser用来对查询语句进行语法分析。

       ◦ QueryParser调用parser进行语法分析,形成查询语法树,放到Query中。

       ◦ IndexSearcher调用search对查询语法树Query进行搜索,得到结果TopScoreDocCollector

二:代码示例(本文重点部分)

      1) 首先是连接数据库的jdbc配置文件信息以及存放索引文件的路径配置信息

jdbc.driverClassName = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://192.168.0.1/dbname?autoReconnect=true&characterEncoding=utf8
jdbc.username = root
jdbc.password = password
jdbc.maxIdle = 2
jdbc.maxActive = 4
jdbc.maxWait = 5000
jdbc.validationQuery = select 0
res.index.indexPath = D\:\\apache-tomcat-6.0.18\\webapps\\test\\testHome\\search\\res\\index1
res.index.mainDirectory = D\:\\apache-tomcat-6.0.18\\webapps\\test\\testHome\\search\\res

     2) 读取资源文件的工具类:

package com.test.common;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**  
 * PropertiesUtil.java
 * @version 1.0
 * @createTime 读取配置文件信息类
 */
public class PropertiesUtil {

	private static String defaultPropertyFilePath = "/test.properties";
	
	private static Map<String,Properties> ppsMap = new HashMap<String,Properties>();
	
	/**
	 * 读取默认文件的配置信息,读key返回value
	 * @param key
	 * @return value
	 */
	public static final String getPropertyValue(String key) {
		Properties pps = getPropertyFile(defaultPropertyFilePath);
		return pps == null ? null : pps.getProperty(key);
	}
	
	/**
	 * 传入filePath读取指定property文件,读key返回value
	 * @param propertyFilePath
	 * @param key
	 * @return value
	 */
	public static String getPropertyValue(String propertyFilePath,String key) {
		if(propertyFilePath == null) {
			propertyFilePath = defaultPropertyFilePath;
		}
		Properties pps = getPropertyFile(propertyFilePath);
		return pps == null ? null : pps.getProperty(key);
	}
	
	/**
	 * 根据path返回property文件,并保存到HashMap中,提高效率
	 * @param propertyFilePath
	 * @return
	 */
	public static Properties getPropertyFile(String propertyFilePath) {
		if(propertyFilePath == null) {
			return null;
		}
		Properties pps = ppsMap.get(propertyFilePath);
		if(pps == null) {
			InputStream in = PropertiesUtil.class.getResourceAsStream(propertyFilePath);
			pps = new Properties();
			try {
				pps.load(in);
			} catch (IOException e) {
				e.printStackTrace();
			}
			ppsMap.put(propertyFilePath, pps);
		}
		
		return pps;
	}
}

      3) Jdbc连接数据库获取Connection工具类,不做分析,直接上代码

package com.test.common;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**  
 * JdbcUtil.java
 * @version 1.0
 * @createTime JDBC获取Connection工具类
 */
public class JdbcUtil {
	
	private static Connection conn = null;
	
	private static final String URL;
	
	private static final String JDBC_DRIVER;
	
	private static final String USER_NAME;
	
	private static final String PASSWORD;
	
	static {
		URL = PropertiesUtil.getPropertyValue("jdbc.url");
		JDBC_DRIVER = PropertiesUtil.getPropertyValue("jdbc.driverClassName");
		USER_NAME = PropertiesUtil.getPropertyValue("jdbc.username");
		PASSWORD = PropertiesUtil.getPropertyValue("jdbc.password");
	}
	
	public static Connection getConnection() {
		try {
			Class.forName(JDBC_DRIVER);
			conn = DriverManager.getConnection(URL, USER_NAME, PASSWORD);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return conn;
	}
	
}

     4) 万事具备,只欠东风了,下面是核心部分,方法都有注释,不多说了,一步步来,我想肯定是没有问题的。代码如下:

package com.test.lucene.logic;

import java.io.File;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.TermVector;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Searcher;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;
import org.wltea.analyzer.lucene.IKSimilarity;

import com.test.common.JdbcUtil;
import com.test.common.PropertiesUtil;
import com.test.lucene.model.SearchBean;

/**  
 * SearchLogic.java
 * @version 1.0
 * @createTime Lucene数据库检索
 */
public class SearchLogic {

	private static Connection conn = null;
	
	private static Statement stmt = null;
	
	private static  ResultSet rs = null;
	
	private String searchDir = PropertiesUtil.getPropertyValue("res.index.indexPath");
	
	private static File indexFile = null;
	
	private static Searcher searcher = null;
	
	private static Analyzer analyzer = null;
	
	/** 索引页面缓冲 */
	private int maxBufferedDocs = 500;
	/**
	 * 获取数据库数据
	 * @return ResultSet
	 * @throws Exception
	 */
	public List<SearchBean> getResult(String queryStr) throws Exception {
		
		List<SearchBean> result = null;
		conn = JdbcUtil.getConnection();
		if(conn == null) {
			throw new Exception("数据库连接失败!");
		}
		String sql = "select articleid,title_en,title_cn,abstract_en,abstract_cn from p2p_jour_article";
		try {
			stmt = conn.createStatement();
			rs = stmt.executeQuery(sql);
			this.createIndex(rs);   //给数据库创建索引,此处执行一次,不要每次运行都创建索引,以后数据有更新可以后台调用更新索引
			TopDocs topDocs = this.search(queryStr);

			ScoreDoc[] scoreDocs = topDocs.scoreDocs;
			
			result = this.addHits2List(scoreDocs);
		} catch(Exception e) {
			e.printStackTrace();
			throw new Exception("数据库查询sql出错! sql : " + sql);
		} finally {
			if(rs != null) rs.close();
			if(stmt != null) stmt.close();
			if(conn != null) conn.close();
		}
		
		return result;
	}
	
	/**
	 * 为数据库检索数据创建索引
	 * @param rs
	 * @throws Exception
	 */
	private void createIndex(ResultSet rs) throws Exception {
		
		Directory directory = null;
		IndexWriter indexWriter = null;
		
		try {
			indexFile = new File(searchDir);
			if(!indexFile.exists()) {
				indexFile.mkdir();
			}
			directory = FSDirectory.open(indexFile);
			analyzer = new IKAnalyzer();
			
			indexWriter = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.UNLIMITED);
			indexWriter.setMaxBufferedDocs(maxBufferedDocs);
			Document doc = null;
			while(rs.next()) {
				doc = new Document();
				Field articleid = new Field("articleid", String.valueOf(rs
						.getInt("articleid")), Field.Store.YES,
						Field.Index.NOT_ANALYZED, TermVector.NO);
				Field abstract_cn = new Field("abstract_cn", rs
						.getString("abstract_cn") == null ? "" : rs
						.getString("abstract_cn"), Field.Store.YES,
						Field.Index.ANALYZED, TermVector.NO);
				doc.add(articleid);
				doc.add(abstract_cn);
				indexWriter.addDocument(doc);
			}
			
			indexWriter.optimize();
			indexWriter.close();
		} catch(Exception e) {
			e.printStackTrace();
		} 
	}
	
	/**
	 * 搜索索引
	 * @param queryStr
	 * @return
	 * @throws Exception
	 */
	private TopDocs search(String queryStr) throws Exception {

		if(searcher == null) {
			indexFile = new File(searchDir);
			searcher = new IndexSearcher(FSDirectory.open(indexFile));	
		}
		searcher.setSimilarity(new IKSimilarity());
		QueryParser parser = new QueryParser(Version.LUCENE_30,"abstract_cn",new IKAnalyzer());
		Query query = parser.parse(queryStr);

		TopDocs topDocs = searcher.search(query, searcher.maxDoc());
		
		return topDocs;
	}
	
	/**
	 * 返回结果并添加到List中
	 * @param scoreDocs
	 * @return
	 * @throws Exception
	 */
	private List<SearchBean> addHits2List(ScoreDoc[] scoreDocs ) throws Exception {
		
		List<SearchBean> listBean = new ArrayList<SearchBean>();
		SearchBean bean = null;
		for(int i=0 ; i<scoreDocs.length; i++) {
			int docId = scoreDocs[i].doc;
			Document doc = searcher.doc(docId);
			bean = new SearchBean();
			bean.setArticleid(doc.get("articleid"));
			bean.setAbstract_cn(doc.get("abstract_cn"));
			listBean.add(bean);
		}
		return listBean;
	}
	
	public static void main(String[] args) {
		SearchLogic logic = new SearchLogic();
		try {
			Long startTime = System.currentTimeMillis();
			List<SearchBean> result = logic.getResult("急性   肺   潮气量   临床试验");
			int i = 0;
			for(SearchBean bean : result) {
				if(i == 10) break;
				System.out.println("bean.name " + bean.getClass().getName()
						+ " : bean.articleid " + bean.getArticleid()
						+ " : bean.abstract_cn " + bean.getAbstract_cn());
				i++;
			}
			System.out.println("searchBean.result.size : " + result.size());
			
			Long endTime = System.currentTimeMillis();
			System.out.println("查询所花费的时间为:" + (endTime-startTime)/1000);
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println(e.getMessage());
		}
	}
}

     5) 第四步用到了一个SearchBean,其实这就是一个javabean文件,包含两个String类型(articleid和abstract_cn)的set、get方法,自己回去补上吧。

        顺便说下数据库表结构:

            tablename随便取,但要跟上面查询中的表对应

            表字段:articleid  int 类型

                        abstract_cn   varchar类型

      对表字段没有太严格的定义,本来就是用来测试的。

     6) 最后给大家提供所使用到的jar包列表:

         IKAnalyzer3.2.5Stable.jar(一位好心人建议我升级一下jar包,呵呵,最新的jar包名为:IKAnalyzer3.2.8.jar ,谢谢了!)

         lucene-analyzers-3.0.2

         lucene-core-3.0.2

         lucene-highlighter-3.0.2

         lucene-memory-3.0.2

         lucene-queries-3.0.2

         mysql-connector-java-5.0.8-bin

   好了,有兴趣的人可以试试吧,代码都经过我测试过了,虽然有些地方代码结构不是特别完整,但只是入门用而已。先有了一个成功能够运行的例子之后才有更多的心情去接着学下去,~_~

分享到:
评论
13 楼 hu123456 2011-04-02  
<div class="quote_title">IrenBJ 写道</div>
<div class="quote_div">
<p>全文分两部分:</p>
<p>一:Lucene简介</p>
<p>      Lucene版本:3.0.2</p>
<p class="MsoPlainText"><span>     全文检索大体分两个部分:索引创建(<span lang="EN-US">Indexing</span>)和搜索索引(<span lang="EN-US">Search</span>)</span></p>
<p><span lang="EN-US">     1. </span><span>索引过程:</span></p>
<p class="MsoPlainText"><span lang="EN-US">        1) </span><span>有一系列被索引文件(此处所指即数据库数据)</span></p>
<p class="MsoPlainText"><span lang="EN-US">        2) </span><span>被索引文件经过语法分析和语言处理形成一系列词<span lang="EN-US">(Term)</span>。</span></p>
<p class="MsoPlainText"><span lang="EN-US">        3) </span><span>经过索引创建形成词典和反向索引表。</span></p>
<p class="MsoPlainText"><span lang="EN-US">        4) </span><span>通过索引存储将索引写入硬盘。</span></p>
<p class="MsoPlainText"><span lang="EN-US">    2. </span><span>搜索过程:</span></p>
<p class="MsoPlainText"><span lang="EN-US">       a) </span><span>用户输入查询语句。</span></p>
<p class="MsoPlainText"><span lang="EN-US">       b) </span><span>对查询语句经过语法分析和语言分析得到一系列词<span lang="EN-US">(Term)</span>。</span></p>
<p class="MsoPlainText"><span lang="EN-US">       c) </span><span>通过语法分析得到一个查询树。</span></p>
<p class="MsoPlainText"><span lang="EN-US">       d) </span><span>通过索引存储将索引读入到内存。</span></p>
<p class="MsoPlainText"><span lang="EN-US">       e) </span><span>利用查询树搜索索引,从而得到每个词<span lang="EN-US">(Term)</span>的文档链表,对文档链表进行交,差,并得到结果文档。</span></p>
<p class="MsoPlainText"><span lang="EN-US">       f) </span><span>将搜索到的结果文档对查询的相关性进行排序。</span></p>
<p class="MsoPlainText"><span lang="EN-US">       g) </span><span>返回查询结果给用户。</span></p>
<p class="MsoPlainText"> </p>
<p class="MsoPlainText"> </p>
<p class="MsoPlainText"><span>   </span><span>• </span><span>索引过程如下:</span></p>
<p class="MsoPlainText"><span>       ◦</span><span> 创建一个<span lang="EN-US">IndexWriter</span>用来写索引文件,它有几个参数,<span lang="EN-US">INDEX_DIR</span>就是索引文件所存放的位置,<span lang="EN-US">Analyzer</span>便是用来对文档进行词法分析和语言处理的。</span></p>
<p class="MsoPlainText"><span>       ◦</span><span> 创建一个<span lang="EN-US">Document</span>代表我们要索引的文档。</span></p>
<p class="MsoPlainText"><span>       ◦</span><span> 将不同的<span lang="EN-US">Field</span>加入到文档中。我们知道,一篇文档有多种信息,如题目,作者,修改时间,内容等。不同类型的信息用不同的<span lang="EN-US">Field</span>来表示,在本例子中,一共有两类信息进行了索引,一个是文件路径,一个是文件内容。其中<span lang="EN-US">FileReader</span>的<span lang="EN-US">SRC_FILE</span>就表示要索引的源文件。</span></p>
<p class="MsoPlainText"><span>       ◦</span><span lang="EN-US"> IndexWriter</span><span>调用函数<span lang="EN-US">addDocument</span>将索引写到索引文件夹中。</span></p>
<p class="MsoPlainText"><span>   • 搜索过程如下:</span></p>
<p class="MsoPlainText"><span>       ◦</span><span lang="EN-US"> IndexReader</span><span>将磁盘上的索引信息读入到内存,<span lang="EN-US">INDEX_DIR</span>就是索引文件存放的位置。</span></p>
<p class="MsoPlainText"><span>       ◦</span><span> 创建<span lang="EN-US">IndexSearcher</span>准备进行搜索。</span></p>
<p class="MsoPlainText"><span>       ◦</span><span> 创建<span lang="EN-US">Analyer</span>用来对查询语句进行词法分析和语言处理。</span></p>
<p class="MsoPlainText"><span>       ◦</span><span> 创建<span lang="EN-US">QueryParser</span>用来对查询语句进行语法分析。</span></p>
<p class="MsoPlainText"><span>       ◦</span><span lang="EN-US"> QueryParser</span><span>调用<span lang="EN-US">parser</span>进行语法分析,形成查询语法树,放到<span lang="EN-US">Query</span>中。</span></p>
<p><span>       ◦</span><span lang="EN-US"> IndexSearcher</span><span lang="EN-US">调用<span lang="EN-US">search</span>对查询语法树<span lang="EN-US">Query</span>进行搜索,得到结果TopScoreDocCollector</span><span>。</span></p>
<p>二:代码示例(本文重点部分)</p>
<p>      1) 首先是连接数据库的jdbc配置文件信息以及存放索引文件的路径配置信息</p>
<pre name="code" class="test.properties">jdbc.driverClassName = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://192.168.0.1/dbname?autoReconnect=true&amp;characterEncoding=utf8
jdbc.username = root
jdbc.password = password
jdbc.maxIdle = 2
jdbc.maxActive = 4
jdbc.maxWait = 5000
jdbc.validationQuery = select 0
res.index.indexPath = D\:\\apache-tomcat-6.0.18\\webapps\\test\\testHome\\search\\res\\index1
res.index.mainDirectory = D\:\\apache-tomcat-6.0.18\\webapps\\test\\testHome\\search\\res
</pre>
<p>     2) 读取资源文件的工具类:</p>
<pre name="code" class="java">package com.test.common;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/** 
* PropertiesUtil.java
* @version 1.0
* @createTime 读取配置文件信息类
*/
public class PropertiesUtil {

private static String defaultPropertyFilePath = "/test.properties";

private static Map&lt;String,Properties&gt; ppsMap = new HashMap&lt;String,Properties&gt;();

/**
* 读取默认文件的配置信息,读key返回value
* @param key
* @return value
*/
public static final String getPropertyValue(String key) {
Properties pps = getPropertyFile(defaultPropertyFilePath);
return pps == null ? null : pps.getProperty(key);
}

/**
* 传入filePath读取指定property文件,读key返回value
* @param propertyFilePath
* @param key
* @return value
*/
public static String getPropertyValue(String propertyFilePath,String key) {
if(propertyFilePath == null) {
propertyFilePath = defaultPropertyFilePath;
}
Properties pps = getPropertyFile(propertyFilePath);
return pps == null ? null : pps.getProperty(key);
}

/**
* 根据path返回property文件,并保存到HashMap中,提高效率
* @param propertyFilePath
* @return
*/
public static Properties getPropertyFile(String propertyFilePath) {
if(propertyFilePath == null) {
return null;
}
Properties pps = ppsMap.get(propertyFilePath);
if(pps == null) {
InputStream in = PropertiesUtil.class.getResourceAsStream(propertyFilePath);
pps = new Properties();
try {
pps.load(in);
} catch (IOException e) {
e.printStackTrace();
}
ppsMap.put(propertyFilePath, pps);
}

return pps;
}
}
</pre>
<p>      3) Jdbc连接数据库获取Connection工具类,不做分析,直接上代码</p>
<pre name="code" class="java">package com.test.common;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/** 
* JdbcUtil.java
* @version 1.0
* @createTime JDBC获取Connection工具类
*/
public class JdbcUtil {

private static Connection conn = null;

private static final String URL;

private static final String JDBC_DRIVER;

private static final String USER_NAME;

private static final String PASSWORD;

static {
URL = PropertiesUtil.getPropertyValue("jdbc.url");
JDBC_DRIVER = PropertiesUtil.getPropertyValue("jdbc.driverClassName");
USER_NAME = PropertiesUtil.getPropertyValue("jdbc.username");
PASSWORD = PropertiesUtil.getPropertyValue("jdbc.password");
}

public static Connection getConnection() {
try {
Class.forName(JDBC_DRIVER);
conn = DriverManager.getConnection(URL, USER_NAME, PASSWORD);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}

}
</pre>
<p>     4) 万事具备,只欠东风了,下面是核心部分,方法都有注释,不多说了,一步步来,我想肯定是没有问题的。代码如下:</p>
<pre name="code" class="java">package com.test.lucene.logic;

import java.io.File;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.TermVector;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Searcher;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;
import org.wltea.analyzer.lucene.IKSimilarity;

import com.test.common.JdbcUtil;
import com.test.common.PropertiesUtil;
import com.test.lucene.model.SearchBean;

/** 
* SearchLogic.java
* @version 1.0
* @createTime Lucene数据库检索
*/
public class SearchLogic {

private static Connection conn = null;

private static Statement stmt = null;

private static  ResultSet rs = null;

private String searchDir = PropertiesUtil.getPropertyValue("res.index.indexPath");

private static File indexFile = null;

private static Searcher searcher = null;

private static Analyzer analyzer = null;

/** 索引页面缓冲 */
private int maxBufferedDocs = 500;
/**
* 获取数据库数据
* @return ResultSet
* @throws Exception
*/
public List&lt;SearchBean&gt; getResult(String queryStr) throws Exception {

List&lt;SearchBean&gt; result = null;
conn = JdbcUtil.getConnection();
if(conn == null) {
throw new Exception("数据库连接失败!");
}
String sql = "select articleid,title_en,title_cn,abstract_en,abstract_cn from p2p_jour_article";
try {
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
this.createIndex(rs);   //给数据库创建索引,此处执行一次,不要每次运行都创建索引,以后数据有更新可以后台调用更新索引
TopDocs topDocs = this.search(queryStr);

ScoreDoc[] scoreDocs = topDocs.scoreDocs;

result = this.addHits2List(scoreDocs);
} catch(Exception e) {
e.printStackTrace();
throw new Exception("数据库查询sql出错! sql : " + sql);
} finally {
if(rs != null) rs.close();
if(stmt != null) stmt.close();
if(conn != null) conn.close();
}

return result;
}

/**
* 为数据库检索数据创建索引
* @param rs
* @throws Exception
*/
private void createIndex(ResultSet rs) throws Exception {

Directory directory = null;
IndexWriter indexWriter = null;

try {
indexFile = new File(searchDir);
if(!indexFile.exists()) {
indexFile.mkdir();
}
directory = FSDirectory.open(indexFile);
analyzer = new IKAnalyzer();

indexWriter = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.UNLIMITED);
indexWriter.setMaxBufferedDocs(maxBufferedDocs);
Document doc = null;
while(rs.next()) {
doc = new Document();
Field articleid = new Field("articleid", String.valueOf(rs
.getInt("articleid")), Field.Store.YES,
Field.Index.NOT_ANALYZED, TermVector.NO);
Field abstract_cn = new Field("abstract_cn", rs
.getString("abstract_cn") == null ? "" : rs
.getString("abstract_cn"), Field.Store.YES,
Field.Index.ANALYZED, TermVector.NO);
doc.add(articleid);
doc.add(abstract_cn);
indexWriter.addDocument(doc);
}

indexWriter.optimize();
indexWriter.close();
} catch(Exception e) {
e.printStackTrace();
}
}

/**
* 搜索索引
* @param queryStr
* @return
* @throws Exception
*/
private TopDocs search(String queryStr) throws Exception {

if(searcher == null) {
indexFile = new File(searchDir);
searcher = new IndexSearcher(FSDirectory.open(indexFile));
}
searcher.setSimilarity(new IKSimilarity());
QueryParser parser = new QueryParser(Version.LUCENE_30,"abstract_cn",new IKAnalyzer());
Query query = parser.parse(queryStr);

TopDocs topDocs = searcher.search(query, searcher.maxDoc());

return topDocs;
}

/**
* 返回结果并添加到List中
* @param scoreDocs
* @return
* @throws Exception
*/
private List&lt;SearchBean&gt; addHits2List(ScoreDoc[] scoreDocs ) throws Exception {

List&lt;SearchBean&gt; listBean = new ArrayList&lt;SearchBean&gt;();
SearchBean bean = null;
for(int i=0 ; i&lt;scoreDocs.length; i++) {
int docId = scoreDocs[i].doc;
Document doc = searcher.doc(docId);
bean = new SearchBean();
bean.setArticleid(doc.get("articleid"));
bean.setAbstract_cn(doc.get("abstract_cn"));
listBean.add(bean);
}
return listBean;
}

public static void main(String[] args) {
SearchLogic logic = new SearchLogic();
try {
Long startTime = System.currentTimeMillis();
List&lt;SearchBean&gt; result = logic.getResult("急性   肺   潮气量   临床试验");
int i = 0;
for(SearchBean bean : result) {
if(i == 10) break;
System.out.println("bean.name " + bean.getClass().getName()
+ " : bean.articleid " + bean.getArticleid()
+ " : bean.abstract_cn " + bean.getAbstract_cn());
i++;
}
System.out.println("searchBean.result.size : " + result.size());

Long endTime = System.currentTimeMillis();
System.out.println("查询所花费的时间为:" + (endTime-startTime)/1000);
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.getMessage());
}
}
}
</pre>
<p>     5) 第四步用到了一个SearchBean,其实这就是一个javabean文件,包含两个String类型(articleid和abstract_cn)的set、get方法,自己回去补上吧。</p>
<p>        顺便说下数据库表结构:</p>
<p>            tablename随便取,但要跟上面查询中的表对应</p>
<p>            表字段:articleid  int 类型</p>
<p>                        abstract_cn   varchar类型</p>
<p>      对表字段没有太严格的定义,本来就是用来测试的。</p>
<p>     6) 最后给大家提供所使用到的jar包列表:</p>
<p>         IKAnalyzer3.2.5Stable.jar(一位好心人建议我升级一下jar包,呵呵,最新的jar包名为:IKAnalyzer3.2.8.jar ,谢谢了!)</p>
<p>         lucene-analyzers-3.0.2</p>
<p>         lucene-core-3.0.2</p>
<p>         lucene-highlighter-3.0.2</p>
<p>         lucene-memory-3.0.2</p>
<p>         lucene-queries-3.0.2</p>
<p>         mysql-connector-java-5.0.8-bin</p>
<p>   好了,有兴趣的人可以试试吧,代码都经过我测试过了,虽然有些地方代码结构不是特别完整,但只是入门用而已。先有了一个成功能够运行的例子之后才有更多的心情去接着学下去,~_~</p>
</div>
<p> </p>
12 楼 JamesQian 2011-04-01  
非常感谢,对我还需要仔细深入
11 楼 IrenBJ 2011-03-17  
Foxswily 写道

回到正题,字面理解"Lucene检索数据库"是lucene能利用db的索引能力做检索,实在没看出切合题意之处。如果这是Luence入门文章貌似又不够详细,可以参考已有的文章。

哎呀,我说哥们,干嘛把一篇简简单单的文章往那么深入的方面想,并不是每个人都跟你一样对全文检索有深入的理解或者接触广。还得照顾一下刚开始学又没有这方面资料的人吧,适时也要站在基层的角度考虑一下老百姓的需求,我这篇文章的目的就出于此,对于初学者入门并没有误导的层面。
10 楼 Foxswily 2011-03-17  
IrenBJ 写道

标题很清晰的写着“入门篇”,index融合问题不在本文范围之内。
Lucene检索数据库的含义指的是用户界面输入关键字,从数据库中的表数据进行检索相关包含用户输入关键字的数据,并返回给用户,该检索过程包含两步
1.将相关的表数据根据一定的条件过滤后生产结果集,然后由Lucene创建索引,生成索引文件
2.根据用户提供的关键字从索引文件中查询数据,这个返回的数据便是用户需要查询的结果。
我认为很切合题意。


好吧,聊聊检索,提到检索肯定是有数据源了,按标题和文章提到的数据源应该是数据库吧,暂且不提数据的数据从何而来。对Lucene来说,不论xml、csv或db数据源没什么区别,核心在创建了索引之后跟数据源已经关系不大(尤其是Field.Store.YES这种保存字段值的方式),在次之后的检索是lucene自己的能力。

lz提到的两步对此也描述的很清楚,外加文中注释:
//给数据库创建索引,此处执行一次,不要每次运行都创建索引,以后数据有更新可以后台调用更新索引  


看来lz也认同,正常情况下建立索引和检索应该是分开的。

回到正题,字面理解"Lucene检索数据库"是lucene能利用db的索引能力做检索,实在没看出切合题意之处。如果这是Luence入门文章貌似又不够详细,可以参考已有的文章。

http://www.iteye.com/search?type=all&query=lucene&sort=

http://www.iteye.com/search?type=all&query=lucene+%E5%85%A5%E9%97%A8

9 楼 IrenBJ 2011-03-17  
程序新手 写道
想问几个问题
   (1) 如何区相同数据库中的不同的表,简历索引库的时候,可不可以把根据不同的表,创建不同的索引库,查询的时候,可不可以根据不同的需求查询不同的索引库
   (2)不同数据库情况下存放不同的表,需求同上


1)Lucene创建索引是由用户自己定义存储索引路径,所以不同的表数据可以分别创建不同的索引文件以区分,自然在查询的时候便可逻辑控制查询哪些数据。
2)只要数据能查出来,就可以满足需求。

Foxswily 写道
晨星★~雨泪 写道
Foxswily 写道

大概意思:

取DB数据 -----> Lucene建索引 ------>Lucene检索

整个流程Lucene跟DB没半毛钱关系,更谈不上检索数据库了,跟正常的Lucene应用有甚区别。

没找到“Lucene检索数据库”的核心内容



不知道 兄弟说的 “Lucene检索数据库”的核心内容 具体指什么?


乍看“Lucene检索数据库”这标题,第一感觉是Lucene和DB融合,尤其是index融合,有nosql倾向。实际内容相去甚远呐,DB检索跟Lucene没什么联系,名不副实。

标题很清晰的写着“入门篇”,index融合问题不在本文范围之内。
Lucene检索数据库的含义指的是用户界面输入关键字,从数据库中的表数据进行检索相关包含用户输入关键字的数据,并返回给用户,该检索过程包含两步
1.将相关的表数据根据一定的条件过滤后生产结果集,然后由Lucene创建索引,生成索引文件
2.根据用户提供的关键字从索引文件中查询数据,这个返回的数据便是用户需要查询的结果。
我认为很切合题意。
8 楼 Foxswily 2011-03-17  
晨星★~雨泪 写道
Foxswily 写道

大概意思:

取DB数据 -----> Lucene建索引 ------>Lucene检索

整个流程Lucene跟DB没半毛钱关系,更谈不上检索数据库了,跟正常的Lucene应用有甚区别。

没找到“Lucene检索数据库”的核心内容



不知道 兄弟说的 “Lucene检索数据库”的核心内容 具体指什么?


乍看“Lucene检索数据库”这标题,第一感觉是Lucene和DB融合,尤其是index融合,有nosql倾向。实际内容相去甚远呐,DB检索跟Lucene没什么联系,名不副实。
7 楼 晨星★~雨泪 2011-03-17  
Foxswily 写道

大概意思:

取DB数据 -----> Lucene建索引 ------>Lucene检索

整个流程Lucene跟DB没半毛钱关系,更谈不上检索数据库了,跟正常的Lucene应用有甚区别。

没找到“Lucene检索数据库”的核心内容



不知道 兄弟说的 “Lucene检索数据库”的核心内容 具体指什么?
6 楼 Foxswily 2011-03-17  

大概意思:

取DB数据 -----> Lucene建索引 ------>Lucene检索

整个流程Lucene跟DB没半毛钱关系,更谈不上检索数据库了,跟正常的Lucene应用有甚区别。

没找到“Lucene检索数据库”的核心内容
5 楼 linliangyi2007 2011-03-16  
楼主是个有心人,支持!

顺便给出IK Analyzer的新版本,各位看官可以下载新的分词器
http://linliangyi2007.iteye.com/blog/941132
4 楼 程序新手 2011-03-16  
想问几个问题
   (1) 如何区相同数据库中的不同的表,简历索引库的时候,可不可以把根据不同的表,创建不同的索引库,查询的时候,可不可以根据不同的需求查询不同的索引库
   (2)不同数据库情况下存放不同的表,需求同上
3 楼 zk1878 2011-03-16  
虽然是入门,但还是不错的,另外jdbc的操作 用apache的dbutils,本人觉得 很爽
2 楼 真liuyake 2011-03-16  
楼主是正在学习吗?正好我也想学学搜索,你能多更新点然后我跟着学。 。
1 楼 qyongkang 2011-03-15  
这个里面好像有一个自带的词库吧?有没有看过能不能用别的词库替换啊

相关推荐

Global site tag (gtag.js) - Google Analytics