??xml version="1.0" encoding="utf-8" standalone="yes"?> 本文以这Ll构q行Q?/p>
1.介绍数据库中Authors表的l构 2.为数据库建立索引 3.为数据库建立查询功能 4.在web界面下进行查询ƈ昄l果 1Q介l数据库中Authors表的l构 字段名称 字段cd 字段含义 Au_id Varchar(11) 作者号 2Qؓ数据库徏立烦?/p>
首先建立一个类TestLucene.java。这个类是Ҏ据库q行建立索引Q编写查询条件等?/p>
当然Q最开始就是徏立数据库q接。连接代码这里就省略了。^_^ 接着Q新Z个方法getResutl(String),它返回的是数据库表Authors的内宏V具体代码如下: 首先要定义一个IndexWriterQ)Q它是将索引写进Lucene自己的数据库中,它存攄位置是有你自己定义的。在定义
IndexWriter是需要指定它的分析器。Lucene自己自带有几个分析器Q例
如:StandarAnalyzer(),SimpleAnalyzer(),StopAnalyzer(){。它作用是对文本q行分析Q判断如何进行切
词?br />
接着Q要定义一个Document。Document相当于二l表中一行数据一栗Document里包含的是Field字段QField相当于数据库中一列,也就是一个属性,一个字Dc?br />
最后应该对IndexWriterq行优化Q方法很单,是writer.optimize(). public Analyzer getAnalyzer(){ 在类TestLucene中徏立一个新的方法searcher(String)Q它q回的是一个搜索的l构集,相当于数据库中的ResultSet一栗它代的参数是你要查询的内容。这里,我把要查询的字段写死了。你可以在添加一个参数表C查询的字Dc?br />
q里主要有两个对象IndexSearcher和Query。IndexSearcher是找到烦引数据库QQuery是处理搜索,它包含了三个参数Q查询内容,查询字段Q分析器?br />
具体代码如下Q?/p>
q里建立一个Jsp面TestLucene.jspq行搜烦?/p>
在TestLucene.jsp面中首先引入类 <% for(int i=0;i<hits.length();i++){ 因ؓ考虑到篇q的问题Q所以该文不会讲的很详细Q也不可能讲的很深?/p>
本文以这Ll构q行Q?/p>
1.介绍数据库中Authors表的l构 2.为数据库建立索引 3.为数据库建立查询功能 4.在web界面下进行查询ƈ昄l果 1Q介l数据库中Authors表的l构 字段名称 字段cd 字段含义 Au_id Varchar(11) 作者号 2Qؓ数据库徏立烦?/p>
首先建立一个类TestLucene.java。这个类是Ҏ据库q行建立索引Q编写查询条件等?/p>
当然Q最开始就是徏立数据库q接。连接代码这里就省略了。^_^ 接着Q新Z个方法getResutl(String),它返回的是数据库表Authors的内宏V具体代码如下: public ResultSet getResult(String sql){ 首先要定义一个IndexWriterQ)Q它是将索引写进Lucene自己的数据库中,它存攄位置是有你自己定义的。在定义
IndexWriter
是需要指定它的分析器。Lucene自己自带有几个分析器Q例如:StandarAnalyzer(),SimpleAnalyzer(),
StopAnalyzer(){。它作用是对文本q行分析Q判断如何进行切词?br />
接着Q要定义一个Document。Document相当于二l表中一行数据一栗Document里包含的是Field字段QField相当于数据库中一列,也就是一个属性,一个字Dc?br />
最后应该对IndexWriterq行优化Q方法很单,是writer.optimize(). public Analyzer getAnalyzer(){ 在类TestLucene中徏立一个新的方法searcher(String)Q它q回的是一个搜索的l构集,相当于数据库中的ResultSet一栗它代的参数是你要查询的内容。这里,我把要查询的字段写死了。你可以在添加一个参数表C查询的字Dc?br />
q里主要有两个对象IndexSearcher和Query。IndexSearcher是找到烦引数据库QQuery是处理搜索,它包含了三个参数Q查询内容,查询字段Q分析器?br />
具体代码如下Q?br />
q里建立一个Jsp面TestLucene.jspq行搜烦?/p>
在TestLucene.jsp面中首先引入类 然后定义一个LuceneTest对象Q获取查询结果集Q?br />
<% for(int i=0;i<hits.length();i++){ 用Lucene-1.3-final为网站数据库建立索引 下是看了lnboy写的《用lucene建立大富论坛的全文索》后写的试代码?br />
?nbsp;lucene 建立索引不可能每ơ都重新开始徏?而是按照新增加的记录,一ơ次的递增
Au_name Varchar(60) 作者名
Phone Char(12) 电话L
Address Varchar(40) 地址
City Varchar(20) 城市
State Char(2) 省䆾
Zip Char(5) 邮编
contract Bit(1) 外键Q关pM大)
表中的部分内容:
public ResultSet getResult(String sql){
try{
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
return rs;
}
catch(SQLException e){
System.out.println(e);
}
return null;
}
然后Qؓ数据库徏立烦引?/p>
具体代码如下Q?/p>
public void Index(ResultSet rs){
try{
IndexWriter writer = new IndexWriter("d:/index/", getAnalyzer(), true);
while(rs.next()){
Document doc=new Document();
doc.add(Field.Keyword("id",rs.getString("au_id")));
doc.add(Field.Text("name",rs.getString("au_name")));
doc.add(Field.UnIndexed("address",rs.getString("address")));
doc.add(Field.UnIndexed("phone",rs.getString("phone")));
doc.add(Field.Text("City",rs.getString("city")));
writer.addDocument(doc);
}
writer.optimize();
writer.close();
}
catch(IOException e){
System.out.println(e);
}
catch(SQLException e){
System.out.println(e);
}
}
return new StandardAnalyzer();
}
3Qؓ数据库徏立查询功?/p>
public Hits seacher(String queryString){
Hits hits=null;;
try{
IndexSearcher is = new IndexSearcher("D:/index/");
Query query=QueryParser.parse(queryString,"City",getAnalyzer());
hits=is.search(query);
}catch(Exception e){
System.out.print(e);
}
return hits;
}
4Q在web界面下进行查询ƈ昄l果
<%@ page import="lucenetest.LucentTest"%>
<%@ page import="org.apache.lucene.search.*,org.apache.lucene.document.*" %>
然后定义一个LuceneTest对象Q获取查询结果集Q?/p>
LucentTest lucent=new LucentTest();
Hits hits=lucent.seacher(request.getParameter("queryString"));
定义一个FormQ徏立一个查询环境:
<form action="TestLucene.jsp">
<input type="text" name="queryString"/>
<input type="submit" value="搜烦"/>
</form>
昄查询l果Q?/p>
<table>
<%if(hits!=null){%>
<tr>
<td>作者号</td>
<td>作者名</td>
<td>地址</td>
<td>电话L</td>
</tr>
Document doc=hits.doc(i);
%>
<tr>
<td><%=doc.get("id") %></td>
<td><%=doc.get("name") %></td>
<td><%=doc.get("address") %></td>
<td><%=doc.get("phone") %></td>
</tr>
<% }}%>
</table>
]]>
Document doc = new Document();
q根据你的需要,用户信息的各个字段对应luncene document中的field q行dQ如Q?
doc.add(new Field("NAME","USERNAME",Field.Store.YES,Field.Index.UN_TOKENIZED));
然后该条doc加入到烦引中Q?如: luceneWriter.addDocument(doc);
q样徏立了lucene的烦引库
3.~写对烦引库的搜索程序(看lucene文档Q,通过对lucene的烦引库的查找,你可以快速找到对应记录的ID
4.通过ID到数据库中查扄兌?
LuceneQ作ZU全文搜索的辅助工具Qؓ我们q行条g搜烦Q无论是像Google,Baidu之类的搜索引擎,q是论坛中的搜烦功能Q还是其?
C/S架构的搜索,都带来了极大的便利和比较高的效率。本文主要是利用Lucene对MS Sql Server
2000q行建立索引Q然后进行全文烦引。至于数据库的内容,可以是网늚内容Q还是其它的。本文中数据库的内容是图书馆理pȝ中的某个作者表Q?
Authors表?
Au_name Varchar(60) 作者名
Phone Char(12) 电话L
Address Varchar(40) 地址
City Varchar(20) 城市
State Char(2) 省䆾
Zip Char(5) 邮编
contract Bit(1) 外键Q关pM大)
表中的部分内容:
try{
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
return rs;
}
catch(SQLException e){
System.out.println(e);
}
return null;
}
然后Qؓ数据库徏立烦引?/p>
具体代码如下Q?br />
public void Index(ResultSet rs){
try{
IndexWriter writer = new IndexWriter("d:/index/", getAnalyzer(), true);
while(rs.next()){
Document doc=new Document();
doc.add(Field.Keyword("id",rs.getString("au_id")));
doc.add(Field.Text("name",rs.getString("au_name")));
doc.add(Field.UnIndexed("address",rs.getString("address")));
doc.add(Field.UnIndexed("phone",rs.getString("phone")));
doc.add(Field.Text("City",rs.getString("city")));
writer.addDocument(doc);
}
writer.optimize();
writer.close();
}
catch(IOException e){
System.out.println(e);
}
catch(SQLException e){
System.out.println(e);
}
}
return new StandardAnalyzer();
}
3Qؓ数据库徏立查询功?/p>
public Hits seacher(String queryString){
Hits hits=null;;
try{
IndexSearcher is = new IndexSearcher("D:/index/");
Query query=QueryParser.parse(queryString,"City",getAnalyzer());
hits=is.search(query);
}catch(Exception e){
System.out.print(e);
}
return hits;
}
4Q在web界面下进行查询ƈ昄l果
<%@ page import="lucenetest.LucentTest"%>
<%@ page import="org.apache.lucene.search.*,org.apache.lucene.document.*" %>
LucentTest lucent=new LucentTest();
Hits hits=lucent.seacher(request.getParameter("queryString"));
定义一个FormQ徏立一个查询环境:
<form action="TestLucene.jsp">
<input type="text" name="queryString"/>
<input type="submit" value="搜烦"/>
</form>
昄查询l果Q?br />
<table>
<%if(hits!=null){%>
<tr>
<td>作者号</td>
<td>作者名</td>
<td>地址</td>
<td>电话L</td>
</tr>
Document doc=hits.doc(i);
%>
<tr>
<td><%=doc.get("id") %></td>
<td><%=doc.get("name") %></td>
<td><%=doc.get("address") %></td>
<td><%=doc.get("phone") %></td>
</tr>
<% }}%>
</table>
为数据库cwb.mdb建立全文索引的indexdb.jsp
<%@ page import ="org.apache.lucene.analysis.standard.*" %>
<%@ page import="org.apache.lucene.index.*" %>
<%@ page import="org.apache.lucene.document.*" %>
<%@ page import="lucene.*" %>
<%@ page contentType="text/html; charset=GBK" %>
<%
long start = System.currentTimeMillis();
String aa=getServletContext().getRealPath("/")+"index";
IndexWriter writer = new IndexWriter(aa, new StandardAnalyzer(), true);
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver").newInstance();
;DBQ=d:""Tomcat 5.0""webapps""zz3zcwbwebhome""WEB-INF""cwb.mdb";
Connection conn = DriverManager.getConnection(url);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(
"select Article_id,Article_name,Article_intro from Article");
while (rs.next()) {
writer.addDocument(mydocument.Document(rs.getString("Article_id"),
rs.getString("Article_name"),rs.getString("Article_intro")));
}
rs.close();
stmt.close();
conn.close();
out.println("索引创徏完毕");
writer.optimize();
writer.close();
out.print(System.currentTimeMillis() - start);
out.println(" total milliseconds");
}
catch (Exception e) {
out.println(" 出错?nbsp;" + e.getClass() +
""n 错误信息? " + e.getMessage());
}
%>
用于昄查询l果的aftsearch.jsp
<%@ page import="org.apache.lucene.search.*" %>
<%@ page import="org.apache.lucene.document.*" %>
<%@ page import="lucene.*" %>
<%@ page import = "org.apache.lucene.analysis.standard.*" %>
<%@ page import="org.apache.lucene.queryParser.QueryParser" %>
<%@ page contentType="text/html; charset=GBK" %>
<%
String keyword=request.getParameter("keyword");
keyword=new String(keyword.getBytes("ISO8859_1"));
out.println(keyword);
try {
String aa=getServletContext().getRealPath("/")+"index";
Searcher searcher = new IndexSearcher(aa);
Query query = QueryParser.parse(keyword, "Article_name", new StandardAnalyzer());
out.println("正在查找: " + query.toString("Article_name")+"<br>");
Hits hits = searcher.search(query);
System.out.println(hits.length() + " total matching documents");
java.text.NumberFormat format = java.text.NumberFormat.getNumberInstance();
for (int i = 0; i < hits.length(); i++) {
//开始输出查询结?nbsp;
Document doc = hits.doc(i);
out.println(doc.get("Article_id"));
out.println("准确度ؓQ? + format.format(hits.score(i) * 100.0) + "%");
out.println(doc.get("Article_name")+"<br>");
// out.println(doc.get("Article_intro"));
}
}catch (Exception e) {
out.println(" 出错?nbsp;" + e.getClass() +""n 错误信息? " + e.getMessage());
}
%>
辅助c:
package lucene;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.DateField;
public class mydocument {
public static Document Document(String Article_id,String Article_name,String Article_intro){
Document doc = new Document();
doc.add(Field.Keyword("Article_id", Article_id));
doc.add(Field.Text("Article_name", Article_name));
doc.add(Field.Text("Article_intro", Article_intro));
return doc;
}
public mydocument() {
}
}
用lucene为数据库搜烦建立增量索引
建立索引的IndexWriterc?有三个参?nbsp;
IndexWriter writer = new IndexWriter(path, new StandardAnalyzer(),isEmpty);
其中W三个参数是bool型的,指定它可以确定是增量索引,q是重徏索引.
对于从数据库中读取的记录,譬如要ؓ文章建立索引,我们可以记录文章的id?然后下次再次建立索引的时候读取存下的id?从此id后往下l增加烦?逻辑如下.
建立增量索引,主要代码如下
{
Statement myStatement = null;
String articleId="0";
//d文g,获得文章idL,q里只存最后一烦引的文章id
try {
FileReader fr = new FileReader("**.txt");
BufferedReader br = new BufferedReader(fr);
articleId=br.readLine();
if(articleId==null||articleId=="")
articleId="0";
br.close();
fr.close();
} catch (IOException e) {
System.out.println("error343!");
e.printStackTrace();
}
try {
//sql语句,Ҏidd下面的内?/span>
String sqlText = "*****"+articleId;
myStatement = conn.createStatement();
ResultSet rs = myStatement.executeQuery(sqlText);
//写烦?/span>
while (rs.next()) {
Document doc = new Document();
doc.add(Field.Keyword("**", DateAdded));
doc.add(Field.Keyword("**", articleid));
doc.add(Field.Text("**", URL));
doc.add(Field.Text("**", Content));
doc.add(Field.Text("**", Title));
try{
writer.addDocument(doc);
}
catch(IOException e){
e.printStackTrace();
}
//我索引的最后一文章的id写入文g
try {
FileWriter fw = new FileWriter("**.txt");
PrintWriter out = new PrintWriter(fw);
out.close();
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
ind.Close();
System.out.println("ok.end");
}
catch (SQLException e){
e.printStackTrace();
}
finally {
//数据库关闭操?/span>
}
}
然后控制是都建立增量索引的时候根据能否都到id值来讄IndexWriter的第三个参数为true 或者是false
try {
FileReader fr = new FileReader("**.txt");
BufferedReader br = new BufferedReader(fr);
if(br.readLine()!= null) {
isEmpty = false;
}
br.close();
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
writer = new IndexWriter(Directory, new StandardAnalyzer(),isEmpty);
]]>
<html>
<body>
<form name="form1" method="post" action="search.jsp">
误入关键字Q?lt;input type="text" name="keyword">
<input type="submit" name="Submit" value="提交">
</form>
</body>
</html>
二、进行搜索和昄l果的search.jsp <%@ page contentType="text/html; charset=gb2312" %>
<%@ page import="java.util.*" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import = "org.apache.lucene.analysis.standard.StandardAnalyzer" %>
<%@ page import="org.apache.lucene.index.IndexReader" %>
<%@ page import="org.apache.lucene.document.Document" %>
<%@ page import="org.apache.lucene.search.IndexSearcher" %>
<%@ page import="org.apache.lucene.search.Hits" %>
<%@ page import="org.apache.lucene.search.Query" %>
<%@ page import="page.Pagination" %> <%@ page import="org.apache.lucene.queryParser.QueryParser" %>
<%@ page import ="org.apache.lucene.analysis.Analyzer" %>
<%
String queryString = request.getParameter("keyword");
if (queryString == null||queryString.length()==0){
out.println("搜烦关键字不能ؓI?);
}else{
queryString=new String(queryString.getBytes("ISO8859_1"));
String indexPath=getServletContext().getRealPath("/")+"index";
boolean error = false;
Document doc;
IndexSearcher searcher = null;
Query query = null;
Hits hits = null;
try {
searcher = new IndexSearcher(IndexReader.open(indexPath));
} catch (Exception e) {
out.print("没有扑ֈ索引文gQ?);
out.print(e.getMessage());
error = true;
}
if (error == false) {
Analyzer analyzer = new StandardAnalyzer();
try {
query = QueryParser.parse(queryString, "Article_name", analyzer);
} catch (Exception e) {
out.print(e.getMessage());
error = true;
}
}
if (error == false && searcher != null) {
hits = searcher.search(query);
if (hits.length() == 0) {
out.print("对不P没有扑ֈ你所需要的资源. ");
error = true;
}
}
if (error == false && searcher != null) {
out.print("搜烦关键字:"+ queryString+ "");
//PaginationcL|上下蝲的,需要传递一个向量,你可以改,q样׃用做二遍?
Vector list=new Vector();
for(int i=0;i< hits.length();i++){
doc = hits.doc(i);
list.add(doc);
}
out.print("扑ֈ的资?/font>");
Pagination pagination = null;
String pageNumber = request.getParameter("pageNumber");
int showItemNumber = 10;
if (pageNumber == null) {
pageNumber = "1";
}
String HTML = "";
if (list != null && list.size() > 0) {
pagination = new Pagination();
pagination.setPageNumber(Integer.parseInt(pageNumber));
pagination.setShowItemNumber(showItemNumber);
pagination.setVisitPageURL("search.jsp?keyword="+queryString);
list =(Vector) pagination.interceptListByStarItemNumber(list);
for(int i=0;i< list.size();i++)
{
doc =(Document) list.get(i);
String A_id=doc.get("Article_id");
String doctitle = doc.get("Article_name");
String url = doc.get("File_name")+"?id="+A_id;
out.print("< a +doctitle+"");
}
HTML = pagination.buildHTML("600");
out.print(HTML);
}
}
}
本文? 目的不在于对Lucene的概念和设计q些q行介绍Q仅在于介绍怎么样去使用Lucene来达到自己想要的几种常见的全文检索的需求,如果x入了? Lucene的话本文不会带给你什么收L。看完本文后x深入的了解Lucene误问:http://lucene.apache.org
一. 概述
随着pȝ信息的越来越多,怎么样从q些信息h中捞赯己想要的那一栚w变得非帔R要了Q全文检索是通常用于解决此类问题的方案,?/span>Lucene则ؓ实现全文索的工具QQ何应用都可通过嵌入它来实现全文索?/span>
? 环境搭徏
?/span>lucene.apache.org上下载最新版本的lucene.jarQ将?/span>jar作ؓ目?/span>build pathQ那么在目中就可以直接使用lucene了?/span>
? 使用说明
3.1. 基本概念
q里介绍的主要ؓ在用中l常到一些概念,以大安比较熟悉的数据库来进行类比的讲解Q?/span>Luceneq行全文索的q程有点cM数据库的q个q程Q?/span>table---à查询相应的字D|查询条g----àq回相应的记录,首先?/span>IndexWriterQ通过它徏立相应的索引表,相当于数据库中的tableQ在构徏此烦引表旉指定的ؓ该烦引表采用何种方式q行构徏Q也是说对于其中的记录的字D以什么方式来q行格式的划分,q个?/span>Lucene中称?/span>AnalyzerQ?/span>Lucene提供了几U环境下使用?/span>AnalyzerQ?/span>SimpleAnalyzer?/span>StandardAnalyzer?/span>GermanAnalyzer{,其中StandardAnalyzer是经怋用的Q因为它提供了对于中文的支持Q在表徏好后我们需要往里面插入用于索引的记录,?/span>Lucene中这个称?/span>DocumentQ有点类似数据库?/span>table的一行记录,记录中的字段的添加方法,?/span>Lucene中称?/span>FieldQ这个和数据库中基本一P对于Field Lucene分ؓ可被索引的,可切分的Q不可被切分的,不可被烦引的几种l合cdQ通过q几个元素基本上可以徏立v索引了。在查询时经常碰到的为另外几个概念,首先?/span>QueryQ?/span>Lucene提供了几U经常可以用到的QueryQ?/span>TermQuery?/span>MultiTermQuery?/span>BooleanQuery?/span>WildcardQuery?/span>PhraseQuery?/span>PrefixQuery?/span>PhrasePrefixQuery?/span>FuzzyQuery?/span>RangeQuery?/span>SpanQueryQ?/span>Query其实也就是指对于需要查询的字段采用什么样的方式进行查询,如模p查询、语义查询、短语查询、范围查询、组合查询等Q还有就?/span>QueryParserQ?/span>QueryParser可用于创Z同的QueryQ还有一?/span>MultiFieldQueryParser支持对于多个字段q行同一关键字的查询Q?/span>IndexSearcher概念指的为需要对何目录下的烦引文件进行何U方式的分析的查询,有点象对数据库的哪种索引表进行查询ƈ按一定方式进行记录中字段的分解查询的概念Q通过IndexSearcher以及Query卛_查询出需要的l果Q?/span>Luceneq回的ؓHits.通过遍历Hits可获取返回的l果?/span>DocumentQ通过Document则可获取Field中的相关信息了?/span>
通过对于上面在徏立烦引和全文索的基本概念的介l希望能让你?/span>Lucene建立一定的了解?/span>
3.2. 全文索需求的实现
索引建立部分的代码:
3.2.1. 对于某字D늚关键字的模糊查询
3.2.2. 对于某字D늚关键字的语义查询
3.2.3. 对于多字D늚关键字的查询
3.2.4. 复合查询(多种查询条g的综合查?/span>)
? ȝ
怿大家通过上面的说明能知道Lucene的一个基本的使用ҎQ在全文索时大家先采用语义时的搜索,先搜索出有意义的内容Q之后再q行模糊之类的搜索,^_^Q这个还是需要根据搜索的需求才能定了,Luceneq提供了很多其他更好用的ҎQ这个就{待大家在用的q程中自己去q一步的摸烦了,比如对于Lucene本n提供?/span>Query的更熟练的掌握,对于Filter?/span>Sorter的用,自己扩展实现AnalyzerQ自己实?/span>Query{等Q甚臛_以去了解一些关于搜索引擎的技?/span>(切词、烦引排?/span> etc){等?来源QBlueDavy之技术Blog)
该分词库使用很简单,先初试化该类
ChineseSegmenter seg = ChineseSegmenter.getGBSegmenter();
然后调用seg.segmentLine("要分词的中文D?, " ")//W二个参Cؓ分词之间以什么间?br />
譬如
因ؓ考虑到篇q的问题Q所以该文不会讲的很详细Q也不可能讲的很深?/p>
本文以这Ll构q行Q?/p>
1.介绍数据库中Authors表的l构
2.为数据库建立索引
3.为数据库建立查询功能
4.在web界面下进行查询ƈ昄l果
1Q介l数据库中Authors表的l构
字段名称 字段cd 字段含义
Au_id Varchar(11) 作者号
Au_name Varchar(60) 作者名
Phone Char(12) 电话L
Address Varchar(40) 地址
City Varchar(20) 城市
State Char(2) 省䆾
Zip Char(5) 邮编
contract Bit(1) 外键Q关pM大)
表中的部分内容:
2Qؓ数据库徏立烦?/p>
首先建立一个类TestLucene.java。这个类是Ҏ据库q行建立索引Q编写查询条件等?/p>
当然Q最开始就是徏立数据库q接。连接代码这里就省略了。^_^
接着Q新Z个方法getResutl(String),它返回的是数据库表Authors的内宏V具体代码如下:
public ResultSet getResult(String sql){
try{
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
return rs;
}
catch(SQLException e){
System.out.println(e);
}
return null;
}
然后Qؓ数据库徏立烦引?/p>
首先要定义一个IndexWriterQ)Q它是将索引写进Lucene自己的数据库中,它存攄位置是有你自己定义的。在定义IndexWriter
是需要指定它的分析器。Lucene自己自带有几个分析器Q例如:StandarAnalyzer(),SimpleAnalyzer(),
StopAnalyzer(){。它作用是对文本q行分析Q判断如何进行切词?br />
接着Q要定义一个Document。Document相当于二l表中一行数据一栗Document里包含的是Field字段QField相当于数据库中一列,也就是一个属性,一个字Dc?br />
最后应该对IndexWriterq行优化Q方法很单,是writer.optimize().
具体代码如下Q?br />
public void Index(ResultSet rs){
try{
IndexWriter writer = new IndexWriter("d:/index/", getAnalyzer(), true);
while(rs.next()){
Document doc=new Document();
doc.add(Field.Keyword("id",rs.getString("au_id")));
doc.add(Field.Text("name",rs.getString("au_name")));
doc.add(Field.UnIndexed("address",rs.getString("address")));
doc.add(Field.UnIndexed("phone",rs.getString("phone")));
doc.add(Field.Text("City",rs.getString("city")));
writer.addDocument(doc);
}
writer.optimize();
writer.close();
}
catch(IOException e){
System.out.println(e);
}
catch(SQLException e){
System.out.println(e);
}
}
public Analyzer getAnalyzer(){
return new StandardAnalyzer();
}
3Qؓ数据库徏立查询功?/p>
在类TestLucene中徏立一个新的方法searcher(String)Q它q回的是一个搜索的l构集,相当于数据库中的ResultSet一栗它代的参数是你要查询的内容。这里,我把要查询的字段写死了。你可以在添加一个参数表C查询的字Dc?br />
q里主要有两个对象IndexSearcher和Query。IndexSearcher是找到烦引数据库QQuery是处理搜索,它包含了三个参数Q查询内容,查询字段Q分析器?br />
具体代码如下Q?br />
public Hits seacher(String queryString){
Hits hits=null;;
try{
IndexSearcher is = new IndexSearcher("D:/index/");
Query query=QueryParser.parse(queryString,"City",getAnalyzer());
hits=is.search(query);
}catch(Exception e){
System.out.print(e);
}
return hits;
}
4Q在web界面下进行查询ƈ昄l果
q里建立一个Jsp面TestLucene.jspq行搜烦?/p>
在TestLucene.jsp面中首先引入类
<%@ page import="lucenetest.LucentTest"%>
<%@ page import="org.apache.lucene.search.*,org.apache.lucene.document.*" %>
然后定义一个LuceneTest对象Q获取查询结果集Q?br />
LucentTest lucent=new LucentTest();
Hits hits=lucent.seacher(request.getParameter("queryString"));
定义一个FormQ徏立一个查询环境:
<form action="TestLucene.jsp">
<input type="text" name="queryString"/>
<input type="submit" value="搜烦"/>
</form>
昄查询l果Q?br />
<table>
<%if(hits!=null){%>
<tr>
<td>作者号</td>
<td>作者名</td>
<td>地址</td>
<td>电话L</td>
</tr>
<% for(int i=0;i<hits.length();i++){
Document doc=hits.doc(i);
%>
<tr>
<td><%=doc.get("id") %></td>
<td><%=doc.get("name") %></td>
<td><%=doc.get("address") %></td>
<td><%=doc.get("phone") %></td>
</tr>
<% }}%>
</table>
用Lucene-1.3-final为网站数据库建立索引
下是看了lnboy写的《用lucene建立大富论坛的全文索》后写的试代码?br />
为数据库cwb.mdb建立全文索引的indexdb.jsp
<%@ page import ="org.apache.lucene.analysis.standard.*" %>
<%@ page import="org.apache.lucene.index.*" %>
<%@ page import="org.apache.lucene.document.*" %>
<%@ page import="lucene.*" %>
<%@ page contentType="text/html; charset=GBK" %>
<%
long start = System.currentTimeMillis();
String aa=getServletContext().getRealPath("/")+"index";
IndexWriter writer = new IndexWriter(aa, new StandardAnalyzer(), true);
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver").newInstance();
?nbsp;lucene 建立索引不可能每ơ都重新开始徏?而是按照新增加的记录,一ơ次的递增
建立索引的IndexWriterc?有三个参?nbsp;
FeaturesQ?span xml:lang="EN-US">
* Very fast indexing, minimal RAM required
* Index compression to 30% of original text
* Indexes text and HTML, document classes available for XML, PDF and RTF
* Search supports phrase and Boolean queries, plus, minus and quote marks, and parentheses
* Allows single and multiple character wildcards anywhere in the search words, fuzzy search, proximity
* Will search for punctuation such as + or
* Field searches for title, author, etc., and date-range searching
* Supports most European languages
* Option to store and display full text of indexed documents
* Search results in relevance order
* APIs for file format conversion, languages and user interfaces
实践dQ?span xml:lang="EN-US">
1)
Java 的程序基本编写完成,实现了对中文的支持。下一步是其攑ֈ WEB 上运行,首先惛_的是使用 JSPQ安装了Apache Tomcat/4.1.24Q默认的发布端口?span xml:lang="EN-US"> 8080。现在面临的一个问题是Q?span xml:lang="EN-US">Apache httpd 的端口是 80Qƈ且我的机器对外只能通过 80 端口q行讉KQ如果将 Tomcat 的发布端口改?span xml:lang="EN-US"> 80 的话Q?span xml:lang="EN-US">httpd 没法对外了Q而其上的 PHP E序也将无法?span xml:lang="EN-US"> 80 端口q行?span xml:lang="EN-US">
对于q个问题Q我惛_两种ҎQ?span xml:lang="EN-US">
1、?PHP 直接调用 Java。需要做的工作是使用 --with-java 重新~译 PHPQ?span xml:lang="EN-US">
2、?mod_jk 做桥接的方式Q将 servlet 引擎l合?span xml:lang="EN-US"> httpd 中。需要做的工作是~译 jakarta-tomcat-connectors-jk-1.2.5-srcQ生?span xml:lang="EN-US"> mod_jk.so l?span xml:lang="EN-US"> httpd 使用Q然后按?Howto 文档 q行 Tomcat?span xml:lang="EN-US">httpd 的配|?span xml:lang="EN-US">
对于W一个方案的试Q?PHP 直接调用 Java
环境
* PHP 4.3.6 prefix=/usr
* Apache 1.3.27 prefix=/usr/local/apache
* j2sdk1.4.1_01 prefix=/usr/local/jdk
配置步骤
1) 安装 JDKQ这个就不多说了Q?span xml:lang="EN-US">?/span> GOOGLE 可以搜烦斚w的大量文?/span>?span xml:lang="EN-US">
2) 重新~译 PHPQ我?span xml:lang="EN-US"> PHP 版本?span xml:lang="EN-US"> 4.3.6Q?/p>
cd php-4.3.6
./configure --with-java=/usr/local/jdk
make
make install
完成之后Q会?span xml:lang="EN-US"> PHP ?span xml:lang="EN-US"> lib 下(我的是在 /usr/lib/phpQ有?span xml:lang="EN-US"> php_java.jarQ同时在扩展动态库存放的目录下Q我的是?span xml:lang="EN-US"> /usr/lib/php/20020429Q有?span xml:lang="EN-US"> java.so 文g。到q一步需要注意一个问题,有些 PHP 版本生成的是 libphp_java.so 文gQ?span xml:lang="EN-US">extension 的加载只?span xml:lang="EN-US"> libphp_java.soQ直接加?span xml:lang="EN-US"> java.so 可能会出现如下错误:
PHP Fatal error: Unable to load Java Library /usr/local/jdk/jre/lib/i386/libjava.so, error: libjvm.so:
cannot open shared object file: No such file or directory in /home/nio/public_html/java.php on line 2
所以如果生成的?span xml:lang="EN-US"> java.soQ需要创Z个符可接:
ln -s java.so libphp_java.so
3) 修改 Apache Service 启动文gQ我的这个文件ؓ /etc/init.d/httpdQ,在这个文件中加入Q?/p>
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/jdk/jre/lib/i386/server:/usr/local/jdk/jre/lib/i386
正如你所看到的,我的 JDK 装在 /usr/local/jdk 目录下,如果你的不是在此目录Q请做相应改动(下同Q?span xml:lang="EN-US">
4) 修改 PHP 配置文g php.iniQ找?span xml:lang="EN-US"> [Java] 部分q行修改Q?/p>
[Java]
java.class.path = /usr/lib/php/php_java.jar
java.home = /usr/local/jdk
;java.library =
;java.library.path =
extension_dir=/usr/lib/php/20020429/
extension=java.so
我将 java.library ?span xml:lang="EN-US"> java.library.path 都注释掉了,PHP 会自动认?span xml:lang="EN-US"> java.library=/usr/local/jdk/jre/lib/i386/libjava.so?span xml:lang="EN-US">
5) 重新启动 Apache httpd 服务Q?/p>
service httpd restart
试
试脚本 java.php 源代码:
getProperty('java.version').'<br />';
print 'Java vendor=' . $system->getProperty('java.vendor').'<br />';
print 'OS=' . $system->getProperty('os.name') . ' ' .
$system->getProperty('os.version') . ' on ' .
$system->getProperty('os.arch') . '<br />';
>
ȝ
安装配置q算单,但是?span xml:lang="EN-US"> PHP
今天ȝ有些I闲旉Q正好说说第二种ҎQ?mod_jk 做桥接的方式Q将 servlet 引擎l合?span xml:lang="EN-US"> httpd 中?span xml:lang="EN-US">
环境
* PHP 4.3.6 prefix=/usr
* Apache 1.3.27 prefix=/usr/local/apache
* j2sdk1.4.1_01 prefix=/usr/local/jdk
* jakarta-tomcat-4.1.24 prefix=/usr/local/tomcat
* 另外需要下?jakarta-tomcat-connectors-jk-1.2.5-src.tar.gz
配置步骤
1) 安装 JDK ?span xml:lang="EN-US"> TomcatQ这些安装步骤就不多说了?span xml:lang="EN-US">
2) ~译 jakarta-tomcat-connectors-jk-1.2.5-srcQ生?span xml:lang="EN-US"> mod_jk.soQƈ其复制?span xml:lang="EN-US"> apache ?span xml:lang="EN-US"> modules 存放目录Q?/p>
tar xzf jakarta-tomcat-connectors-jk-1.2.5-src.tar.gz
cd jakarta-tomcat-connectors-jk-1.2.5-src/jk/native
./configure --with-apxs=/usr/local/apache/bin/apxs
make
cp apache-1.3/mod_jk.so /usr/local/apache/libexec
3) ~辑 Apache 配置文g /usr/local/apache/conf/httpd.confQ加入:
LoadModule jk_module libexec/mod_jk.so
AddModule mod_jk.c
q个 LoadModule 语句最好放在其?span xml:lang="EN-US"> LoadModule 语句后边?span xml:lang="EN-US">
同时在配|文件后边加入:
# workers.properties 文g所在\径,后边对此文件进行讲?/p>
JkWorkersFile /usr/local/apache/conf/workers.properties
# jk 的日志文件存放\?/p>
JkLogFile /usr/local/apache/log/mod_jk.log
# 讄 jk 的日志?span xml:lang="EN-US"> [debug/error/info]
JkLogLevel info
# 选择日志旉格式
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
# JkOptions 选项讄
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
# JkRequestLogFormat 讄日志的请求格?/p>
JkRequestLogFormat "%w %V %T"
# 映射 /examples/* ?span xml:lang="EN-US"> worker1Q?span xml:lang="EN-US">worker1 ?span xml:lang="EN-US"> workers.properties 文g中定?/p>
JkMount /examples/* worker1
4) ?span xml:lang="EN-US"> /usr/local/apache/conf/ 目录下创?span xml:lang="EN-US"> workers.properties 文gQ其内容如下Q?/p>
# 定义使用 ajp13 ?span xml:lang="EN-US"> worker1
worker.list=worker1
# 讄 worker1 的属性(ajp13Q?/p>
worker.worker1.type=ajp13
worker.worker1.host=localhost
worker.worker1.port=8009
worker.worker1.lbfactor=50
worker.worker1.cachesize=10
worker.worker1.cache_timeout=600
worker.worker1.socket_keepalive=1
worker.worker1.socket_timeout=300
5) 好了Q启?span xml:lang="EN-US"> TomcatQ重启一?span xml:lang="EN-US"> Apache HTTPD ServerQ访问:http://localhost/examples/index.jspQ看看结果如何,?http://localhost:8080/examples/index.jsp 是一L?span xml:lang="EN-US">
提示Q如果不惌别h通过 8080 端口讉KC?span xml:lang="EN-US"> TomcatQ可以将 /usr/lcoal/tomcat/conf/server.xml 配置文g中的如下代码加上注释Q?/p>
<!--
<Connector className="org.apache.coyote.tomcat4.CoyoteConnector"
port="8080" minProcessors="5" maxProcessors="75"
enableLookups="false" redirectPort="8443"
acceptCount="100" debug="0" connectionTimeout="20000"
useURIValidationHack="false" disableUploadTimeout="true" />
-->
然后重新启动 Tomcat 卛_?span xml:lang="EN-US">
对于 Lucene 的初步研I已l过MD|_自己感觉q不是很深入Q但׃旉的关p,一直也没再拿v。应|友的要求,自己实践中写的一些代码脓出来Q希望能对大家有用。程序没有做q一步的优化Q只是很单的实现功能而已Q仅供参考?br />
在实践中Q我以将 PHP 中文手册中的 HTML 文g生成索引Q然后通过一?JSP 对其q行全文索?
生成索引?Java 代码Q?/span>
/**
* PHPDocIndexer.java
* 用于?PHPDoc ?HTML 面生成索引文g?/span>
*/
import java.io.File;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Date;
import java.text.DateFormat;
import java.lang.*;
import org.apache.lucene.analysis.cjk.CJKAnalyzer;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.DateField;
class PHPDocIndexer
{
public static void main(String[] args) throws ClassNotFoundException, IOException
{
try {
Date start = new Date();
IndexWriter writer = new IndexWriter("/home/nio/indexes-phpdoc", new CJKAnalyzer(), true); //索引保存目录Q必d?/span>
indexDocs(writer, new File("/home/nio/phpdoc-zh")); //HTML 文g保存目录
System.out.println("Optimizing ....");
writer.optimize();
writer.close();
Date end = new Date();
System.out.print("Total time: ");
System.out.println(end.getTime() - start.getTime());
} catch (Exception e) {
System.out.println("Class " + e.getClass() + " throws error!/n errmsg: " + e.getMessage());
} //end try
} //end main
public static void indexDocs(IndexWriter writer, File file) throws Exception
{
if (file.isDirectory()) {
String[] files = file.list();
for (int i = 0; i < files.length; i++) {
indexDocs(writer, new File(file, files[i]));
} //end for
} else if (file.getPath().endsWith(".html")) { //只对 HTML 文g做烦?
System.out.print("Add file:" + file + " ....");
// Add html file ....
Document doc = new Document();
doc.add(Field.UnIndexed("file", file.getName())); //索引文g?/span>
doc.add(Field.UnIndexed("modified", DateFormat.getDateTimeInstance().format(new Date(file.lastModified())))); //索引最后修Ҏ?/span>
String title = "";
String content = "";
String status = "start";
FileReader fReader = new FileReader(file);
BufferedReader bReader = new BufferedReader(fReader);
String line = bReader.readLine();
while (line != null) {
content += line;
//截取 HTML 标题 <title>
if ("start" == status && line.equalsIgnoreCase("><TITLE")) {
status = "match";
} else if ("match" == status) {
title = line.substring(1, line.length() - 7);
doc.add(Field.Text("title", title)); //索引标题
status = "end";
} //end if
line = bReader.readLine();
} //end while
bReader.close();
fReader.close();
doc.add(Field.Text("content", content.replaceAll("<[^<>]+>", ""))); //索引内容
writer.addDocument(doc);
System.out.println(" [OK]");
} //end if
}
} //end class
索引生成完之后,需要一个检索页面,下边是搜索页面(search.jspQ的代码Q?/span>
<%@ page language="java" import="javax.servlet.*, javax.servlet.http.*, java.io.*, java.util.Date, java.util.ArrayList, java.util.regex.*, org.apache.lucene.analysis.*, org.apache.lucene.document.*, org.apache.lucene.index.*, org.apache.lucene.search.*, org.apache.lucene.queryParser.*, org.apache.lucene.analysis.Token, org.apache.lucene.analysis.TokenStream, org.apache.lucene.analysis.cjk.CJKAnalyzer, org.apache.lucene.analysis.cjk.CJKTokenizer, com.chedong.weblucene.search.WebLuceneHighlighter" %>
<%@ page contentType="text/html;charset=GB2312" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>PHPDoc - PHP 体中文手册全文检?lt;/title>
<base target="main"><!-- ׃使用?FrameQ所以指?target ?main H口昄 -->
<style>
body {background-color: white; margin: 4px}
body, input, div {font-family: Tahoma; font-size: 9pt}
body, div {line-height: 18px}
u {color: red}
b {color: navy}
form {padding: 0px; margin: 0px}
.txt {border: 1px solid black}
.f {padding: 4px; margin-bottom: 16px; background-color: #E5ECF9; border-top: 1px solid #3366CC; border-bottom: 1px solid #3366CC; text-align: center;}
.d, .o {padding-left: 16px}
.d {color: gray}
.o {color: green}
.o a {color: #7777CC}
</style>
<script language="JavaScript">
function gotoPage(i)
{
document.frm.page.value = i;
document.frm.submit();
} //end function
</script>
</head>
<body>
<%
String keyVal = null;
String pageVal = null;
int offset = 0;
int curPage = 0;
int pages;
final int ROWS = 50;
//获取 GET 参数
try {
byte[] keyValByte = request.getParameter("key").getBytes("ISO8859_1"); //查找关键?/span>
keyVal = new String(keyValByte);
pageVal = request.getParameter("page"); //늠
} catch (Exception e) {
//do nothing;
}
if (keyVal == null)
keyVal = new String("");
%>
<div class="f">
<form name="frm" action="./index.jsp" method="GET" onsubmit="this.page.value='0';return true;" target="_self">
<input type="text" name="key" class="txt" size="40" value="<%=keyVal%>" />
<input type="hidden" name="page" value="<%=pageVal%>" />
<input type="submit" value="?? /><br />
<font color="green">提示Q可使用多个关键字(使用I格隔开Q提高搜索的准确率?lt;/font>
</form>
<script language="JavaScript">
document.frm.key.focus();
</script>
</div>
<%
if (keyVal != null && keyVal.length() > 0) {
try {
curPage = Integer.parseInt(pageVal); //当前页转换成整?/span>
} catch (Exception e) {
//do nothing;
} //end try
try {
Date startTime = new Date();
keyVal = keyVal.toLowerCase().replaceAll("(or|and)", "").trim().replaceAll("http://s+", " AND ");
Searcher searcher = new IndexSearcher("/home/nio/indexes-phpdoc"); //索引目录
Analyzer analyzer = new CJKAnalyzer();
String[] fields = {"title", "content"};
Query query = MultiFieldQueryParser.parse(keyVal, fields, analyzer);
Hits hits = searcher.search(query);
StringReader in = new StringReader(keyVal);
TokenStream tokenStream = analyzer.tokenStream("", in);
ArrayList al = new ArrayList();
for (Token token = tokenStream.next(); token != null; token = tokenStream.next()) {
al.add(token.termText());
} //end for
//总页?/span>
pages = (new Integer(hits.length()).doubleValue() % ROWS != 0) (hits.length() / ROWS) + 1 : (hits.length() / ROWS);
//当前늠
if (curPage < 1)
curPage = 1;
else if (curPage > pages)
curPage = pages;
//起始、终止下?/span>
offset = (curPage - 1) * ROWS;
int end = Math.min(hits.length(), offset + ROWS);
//循环输出查询l果
WebLuceneHighlighter hl = new WebLuceneHighlighter(al);
for (int i = offset; i < end; i++) {
Document doc = hits.doc(i);
%>
<div class="t"><a href="/~nio/phpdoc-zh/<%=doc.get("file")%>"><%=hl.highLight(doc.get("title"))%></a></div>
<div class="d"><%=hl.highLight(doc.get("content").replaceAll("/n", " "), 100)%> ……</div>
<div class="o">
/~nio/phpdoc-zh/<%=doc.get("file")%>
-
<%=doc.get("modified")%>
</div>
<br />
<%
} //end for
searcher.close();
Date endTime = new Date();
%>
<div class="f">
索d耗时 <b><%=((endTime.getTime() - startTime.getTime()) / 1000.0)%></b> U,U有 <b><%=hits.length()%></b> 符合条件的记录Q共 <b><%=pages%></b> ?/span>
<%
if (curPage > 1 && pages > 1) {
%>
|<a href="javascript:gotoPage(<%=(curPage-1)%>);" target="_self">上一?lt;/a>
<%
} //end if
if (curPage < pages && pages > 1) {
%>
|<a href="javascript:gotoPage(<%=(curPage+1)%>)" target="_self">下一?lt;/a>
<%
} //end if
} catch (Exception e) {
%>
<!-- <%=e.getClass()%> D错误Q?lt;%=e.getMessage()%> -->
<%
} //end if
} //end if
%>
</body>
</html>