SlideShare uma empresa Scribd logo
1 de 12
Baixar para ler offline
Lucene 全文检索实践(1)                                                                            页码,1/12




Lucene 全文检索实践(1)
Lucene 是 Apache Jakarta 的一个子项目,是一个全文检索的搜索引擎库。其提供了简单实用的 API,通过这些
API,可以自行编写对文件(TEXT/XML/HTML等)、目录、数据库的全文检索程序。
Features:
* 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


实践任务:
1) 编写 Java 程序 MyIndexer.java,使用 JDBC 取出 MySQL 数据表内容(以某一论坛数据做测试),然后通过
org.apache.lucene.index.IndexWriter 创建索引。
2) 编写 Java 程序 MySearcher.java,通过 org.apache.lucene.search.IndexSearcher 等查询索引。
3) 实现支持中文查询及检索关键字高亮显示。
4) 通过 PHP / Java Integration 实现对 MySearch.java 的调用。
5) 实现对 PHP 手册(简体中文) 的全文检索。




Lucene 全文检索实践(2)
Java 的程序基本编写完成,实现了对中文的支持。下一步是将其放到 WEB 上运行,首先想到的是使用 JSP,安装了
Apache Tomcat/4.1.24,默认的发布端口是 8080。现在面临的一个问题是:Apache httpd 的端口是 80,并且
我的机器对外只能通过 80 端口进行访问,如果将 Tomcat 的发布端口改成 80 的话,httpd 就没法对外了,而其上的
PHP 程序也将无法在 80 端口运行。


对于这个问题,我想到两种方案:
1、使用 PHP 直接调用 Java。需要做的工作是使用 --with-java 重新编译 PHP;
2、使用 mod_jk 做桥接的方式,将 servlet 引擎结合到 httpd 中。需要做的工作是编译 jakarta-tomcat-
connectors-jk-1.2.5-src,生成 mod_jk.so 给 httpd 使用,然后按照 Howto 文档 进行 Tomcat、httpd 的配
置。


对于第一个方案的尝试:使用 PHP 直接调用 Java


环境
* PHP 4.3.6 prefix=/usr
* Apache 1.3.27 prefix=/usr/local/apache
* j2sdk1.4.1_01 prefix=/usr/local/jdk




http://www.lucene.com.cn/sj.htm                                                                2009-9-3
Lucene 全文检索实践(1)                                                                  页码,2/12




配置步骤
1) 安装 JDK,这个就不多说了,到 GOOGLE 可以搜索出这方面的大量文章。


2) 重新编译 PHP,我的 PHP 版本是 4.3.6:

cd php-4.3.6
./configure --with-java=/usr/local/jdk
make
make install


完成之后,会在 PHP 的 lib 下(我的是在 /usr/lib/php)有个 php_java.jar,同时在扩展动态库存放的目录下(我的
是在 /usr/lib/php/20020429)有个 java.so 文件。到这一步需要注意一个问题,有些 PHP 版本生成的是
libphp_java.so 文件,extension 的加载只认 libphp_java.so,直接加载 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


所以如果生成的是 java.so,需要创建一个符号连接:

ln -s java.so libphp_java.so




3) 修改 Apache Service 启动文件(我的这个文件为 /etc/init.d/httpd),在这个文件中加入:

export
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/jdk/jre/lib/i386/server:/usr/local/jdk/jre/lib


正如你所看到的,我的 JDK 装在 /usr/local/jdk 目录下,如果你的不是在此目录,请做相应改动(下同)。


4) 修改 PHP 配置文件 php.ini,找到 [Java] 部分进行修改:

[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 及 java.library.path 都注释掉了,PHP 会自动认为
java.library=/usr/local/jdk/jre/lib/i386/libjava.so。


5) 重新启动 Apache httpd 服务:

service httpd restart




http://www.lucene.com.cn/sj.htm                                                     2009-9-3
Lucene 全文检索实践(1)                                                            页码,3/12



测试
测试脚本 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 />';
?>




总结
安装配置还算简单,但是在 PHP 运行 Java 的速度感觉较慢,所以下定决心开始实践第二个方案。(待续)

Lucene 全文检索实践(3)
今天总算有些空闲时间,正好说说第二种方案:使用 mod_jk 做桥接的方式,将 servlet 引擎结合到 httpd 中。


环境
* 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 与 Tomcat,这些安装步骤就不多说了。


2) 编译 jakarta-tomcat-connectors-jk-1.2.5-src,生成 mod_jk.so,并将其复制到 apache 的 modules 存放目
录:

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 配置文件 /usr/local/apache/conf/httpd.conf,加入:

LoadModule jk_module libexec/mod_jk.so
AddModule mod_jk.c


这个 LoadModule 语句最好放在其他 LoadModule 语句后边。
同时在配置文件后边加入:

# workers.properties 文件所在路径,后边将对此文件进行讲解
JkWorkersFile /usr/local/apache/conf/workers.properties
# jk 的日志文件存放路径
JkLogFile /usr/local/apache/log/mod_jk.log




http://www.lucene.com.cn/sj.htm                                               2009-9-3
Lucene 全文检索实践(1)                                                         页码,4/12



# 设置 jk 的日志级别 [debug/error/info]
JkLogLevel info
# 选择日志时间格式
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
# JkOptions 选项设置
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
# JkRequestLogFormat 设置日志的请求格式
JkRequestLogFormat "%w %V %T"
# 映射 /examples/* 到 worker1,worker1 在 workers.properties 文件中定义
JkMount /examples/* worker1




4) 在 /usr/local/apache/conf/ 目录下创建 workers.properties 文件,其内容如下:

# 定义使用 ajp13 的 worker1
worker.list=worker1


# 设置 worker1 的属性(ajp13)
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) 好了,启动 Tomcat,重启一下 Apache HTTPD Server,访问:http://localhost/examples/index.jsp,看看结
果如何,和 http://localhost:8080/examples/index.jsp 是一样的。


提示:如果不想让别人通过 8080 端口访问到你的 Tomcat,可以将 /usr/lcoal/tomcat/conf/server.xml 配置文件中
的如下代码加上注释:

<!--
<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 即可。


总结
此方案安装配置稍微复杂些,但执行效率要比第一种方案要好很多。所以决定使用这种方案来完成我的 Lucene 全文检索
实践任务。




http://www.lucene.com.cn/sj.htm                                             2009-9-3
Lucene 全文检索实践(1)                                           页码,5/12




Tomcat Service 脚本
在 Linux (我用的是 Redhat)中,如果经常需要启动/关闭 Tomcat 的话,还是创建一个 daemon 来得比较方便,创
建步骤如下:


1) 在 /etc/init.d/ 目录下创建文件 tomcat,代码如下:

# chkconfig: 345 91 10
# description: Tomcat daemon.
#


# 包含函数库
. /etc/rc.d/init.d/functions


# 获取网络配置
. /etc/sysconfig/network


# 检测 NETWORKING 是否为 "yes"
[ "${NETWORKING}" = "no" ] && exit 0


# 设置变量
# $TOMCAT 指向 Tomcat 的安装目录
TOMCAT=/usr/local/tomcat


# $STARTUP 指向 Tomcat 的启动脚本
STARTUP=$TOMCAT/bin/startup.sh


# $SHUTDOWN 指向 Tomcat 的关闭脚本
SHUTDOWN=$TOMCAT/bin/shutdown.sh


# 设置 JAVA_HOME 环境变量,指向 JDK 安装目录
export JAVA_HOME=/usr/local/jdk


# 启动服务函数
start() {
           echo -n $"Starting Tomcat service: "
           $STARTUP
           RETVAL=$?
           echo
}


# 关闭服务函数
stop() {
           action $"Stopping Tomcat service: " $SHUTDOWN
           RETVAL=$?
           echo




http://www.lucene.com.cn/sj.htm                              2009-9-3
Lucene 全文检索实践(1)                                                页码,6/12



}


# 根据参数选择调用
case "$1" in
    start)
             start
             ;;
    stop)
             stop
             ;;
    restart)
             stop
             start
             ;;
    *)
             echo $"Usage: $0 start|stop|restart"
             exit 1
esac


exit 0


2) 修改 tomcat 文件的属性

chown a+x tomcat


3) 生成 service

chkconfig --add tomcat


好了,现在可以通过 service tomcat start 命令启动 Tomcat 了,关闭及重启服务的命令也类似,只是将 start 换成
stop 或 restart。

Lucene 全文检索实践(4)
在几天的研究中,了解了 Lucene 全文检索的一些原理,同时进行了实践,编写了一个论坛的全文检索创建索引程序及用
于搜索的 JSP 程序,另外还写了一个 PHP 手册(简体中文)的全文检索,可以进行多关键字搜索。基本完成了最初定下
的实践任务。

Lucene 全文检索实践(5)
对于 Lucene 的初步研究已经过去一段时间,自己感觉还不是很深入,但由于时间的关系,一直也没再拿起。应网友的要
求,将自己实践中写的一些代码贴出来,希望能对大家有用。程序没有做进一步的优化,只是很简单的实现功能而已,仅供
参考。


在实践中,我以将 PHP 中文手册中的 HTML 文件生成索引,然后通过一个 JSP 对其进行全文检索。
生成索引的 Java 代码:

/**
 * PHPDocIndexer.java
 * 用于对 PHPDoc 的 HTML 页面生成索引文件。




http://www.lucene.com.cn/sj.htm                                  2009-9-3
Lucene 全文检索实践(1)                                                                 页码,7/12



 */
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); //索引保存目录,必须存在
              indexDocs(writer, new File("/home/nio/phpdoc-zh")); //HTML 文件保存目录


              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]));




http://www.lucene.com.cn/sj.htm                                                      2009-9-3
Lucene 全文检索实践(1)                                                                 页码,8/12



            }     //end for
        } else if (file.getPath().endsWith(".html")) {   //只对 HTML 文件做索引
            System.out.print("Add file:" + file + " ....");
            // Add html file ....
            Document doc = new Document();
            doc.add(Field.UnIndexed("file", file.getName()));     //索引文件名
            doc.add(Field.UnIndexed("modified", DateFormat.getDateTimeInstance().format
(new Date(file.lastModified()))));      //索引最后修改时间


            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.jsp)的代码:

<%@ 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,




http://www.lucene.com.cn/sj.htm                                                   2009-9-3
Lucene 全文检索实践(1)                                                                页码,9/12



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 简体中文手册全文检索</title>
     <base target="main"><!-- 由于使用了 Frame,所以指定 target 到 main 窗口显示 -->
     <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 {




http://www.lucene.com.cn/sj.htm                                                   2009-9-3
Lucene 全文检索实践(1)                                                                页码,10/12



     byte[] keyValByte = request.getParameter("key").getBytes("ISO8859_1");   //查找关键字
     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">提示:可使用多个关键字(使用空格隔开)提高搜索的准确率。</font>
     </form>
     <script language="JavaScript">
         document.frm.key.focus();
     </script>
</div>
<%
if (keyVal != null && keyVal.length() > 0) {
     try {
         curPage = Integer.parseInt(pageVal);      //将当前页转换成整数
     } catch (Exception e) {
         //do nothing;
     }   //end try
     try {
         Date startTime = new Date();
         keyVal = keyVal.toLowerCase().replaceAll("(or|and)", "").trim().replaceAll
("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




http://www.lucene.com.cn/sj.htm                                                   2009-9-3
Lucene 全文检索实践(1)                                                             页码,11/12



       //总页数
       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;


       //起始、终止下标
       offset = (curPage - 1) * ROWS;
       int end = Math.min(hits.length(), offset + ROWS);


       //循环输出查询结果
       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">
                  检索总共耗时 <b><%=((endTime.getTime() - startTime.getTime()) / 1000.0)%
></b> 秒,约有 <b><%=hits.length()%></b> 项符合条件的记录,共 <b><%=pages%></b> 页
       <%
       if (curPage > 1 && pages > 1) {
       %>
            | <a href="javascript:gotoPage(<%=(curPage-1)%>);" target="_self">上一页</a>
       <%
       }    //end if
       if (curPage < pages && pages > 1) {
       %>
            | <a href="javascript:gotoPage(<%=(curPage+1)%>)" target="_self">下一页</a>




http://www.lucene.com.cn/sj.htm                                                    2009-9-3
Lucene 全文检索实践(1)                                                页码,12/12



          <%
          }    //end if
     } catch (Exception e) {
     %>
          <!-- <%=e.getClass()%> 导致错误:<%=e.getMessage()%> -->
     <%
     }    //end if
}    //end if
%>
</body>
</html>




在线示例:PHP 手册(简体中文)。




http://www.lucene.com.cn/sj.htm                                   2009-9-3

Mais conteúdo relacionado

Mais procurados

课题一:PHP5.3、PHP5.4的特性介绍与深度挖掘
课题一:PHP5.3、PHP5.4的特性介绍与深度挖掘课题一:PHP5.3、PHP5.4的特性介绍与深度挖掘
课题一:PHP5.3、PHP5.4的特性介绍与深度挖掘
Liu Allen
 
Spring框架,技术详解及使用指导
Spring框架,技术详解及使用指导Spring框架,技术详解及使用指导
Spring框架,技术详解及使用指导
yiditushe
 
Puppet安装测试
Puppet安装测试Puppet安装测试
Puppet安装测试
Yiwei Ma
 
线程与并发
线程与并发线程与并发
线程与并发
Tony Deng
 

Mais procurados (20)

Ali-tomcat
Ali-tomcatAli-tomcat
Ali-tomcat
 
Shell,信号量以及java进程的退出
Shell,信号量以及java进程的退出Shell,信号量以及java进程的退出
Shell,信号量以及java进程的退出
 
课题一:PHP5.3、PHP5.4的特性介绍与深度挖掘
课题一:PHP5.3、PHP5.4的特性介绍与深度挖掘课题一:PHP5.3、PHP5.4的特性介绍与深度挖掘
课题一:PHP5.3、PHP5.4的特性介绍与深度挖掘
 
Jboss连接池原理及调优
Jboss连接池原理及调优Jboss连接池原理及调优
Jboss连接池原理及调优
 
Spring框架,技术详解及使用指导
Spring框架,技术详解及使用指导Spring框架,技术详解及使用指导
Spring框架,技术详解及使用指导
 
Software Engineer Talk
Software Engineer TalkSoftware Engineer Talk
Software Engineer Talk
 
Puppet安装测试
Puppet安装测试Puppet安装测试
Puppet安装测试
 
线程与并发
线程与并发线程与并发
线程与并发
 
現代 IT 人一定要知道的 Ansible 自動化組態技巧 Ⅱ - Roles & Windows
現代 IT 人一定要知道的 Ansible 自動化組態技巧 Ⅱ - Roles & Windows現代 IT 人一定要知道的 Ansible 自動化組態技巧 Ⅱ - Roles & Windows
現代 IT 人一定要知道的 Ansible 自動化組態技巧 Ⅱ - Roles & Windows
 
Lua 语言介绍
Lua 语言介绍Lua 语言介绍
Lua 语言介绍
 
IOS入门分享
IOS入门分享IOS入门分享
IOS入门分享
 
MySQL aio
MySQL aioMySQL aio
MySQL aio
 
自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)
自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)
自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)
 
GNU Autoconf / Automake #1
GNU Autoconf / Automake #1GNU Autoconf / Automake #1
GNU Autoconf / Automake #1
 
Linux chapt3
Linux chapt3Linux chapt3
Linux chapt3
 
善用工具
善用工具善用工具
善用工具
 
AWS EC2 for beginner
AWS EC2 for beginnerAWS EC2 for beginner
AWS EC2 for beginner
 
Effective linux.1.(commandline)
Effective linux.1.(commandline)Effective linux.1.(commandline)
Effective linux.1.(commandline)
 
Gnu
GnuGnu
Gnu
 
OSGi Small Lab
OSGi Small LabOSGi Small Lab
OSGi Small Lab
 

Destaque

2.22 session 23 einheit 5
2.22 session 23 einheit 52.22 session 23 einheit 5
2.22 session 23 einheit 5
nblock
 
John Kauffman Resume 2016 (1)
John Kauffman Resume 2016 (1)John Kauffman Resume 2016 (1)
John Kauffman Resume 2016 (1)
John kauffman
 
CIVIL SOCIETY FALL_WINTER 2016
CIVIL SOCIETY FALL_WINTER 2016CIVIL SOCIETY FALL_WINTER 2016
CIVIL SOCIETY FALL_WINTER 2016
Brittany Snell
 
Teresa beatriz rodríguez aldeamayor
Teresa beatriz rodríguez  aldeamayorTeresa beatriz rodríguez  aldeamayor
Teresa beatriz rodríguez aldeamayor
ABNCFIE VALLADOLID
 

Destaque (19)

استخواں پیش سگاں کی فہمائش
استخواں پیش سگاں کی فہمائشاستخواں پیش سگاں کی فہمائش
استخواں پیش سگاں کی فہمائش
 
2.22 session 23 einheit 5
2.22 session 23 einheit 52.22 session 23 einheit 5
2.22 session 23 einheit 5
 
John Kauffman Resume 2016 (1)
John Kauffman Resume 2016 (1)John Kauffman Resume 2016 (1)
John Kauffman Resume 2016 (1)
 
345 15 26
345 15 26345 15 26
345 15 26
 
Daniela
DanielaDaniela
Daniela
 
CIVIL SOCIETY FALL_WINTER 2016
CIVIL SOCIETY FALL_WINTER 2016CIVIL SOCIETY FALL_WINTER 2016
CIVIL SOCIETY FALL_WINTER 2016
 
O PROCESSO DE INSERÇÃO PROFISSIONAL DE UMA TUTORA VIRTUAL INICIANTE
O PROCESSO DE INSERÇÃO PROFISSIONAL DE UMA TUTORA VIRTUAL INICIANTEO PROCESSO DE INSERÇÃO PROFISSIONAL DE UMA TUTORA VIRTUAL INICIANTE
O PROCESSO DE INSERÇÃO PROFISSIONAL DE UMA TUTORA VIRTUAL INICIANTE
 
Kế toán tài sản cố định, Công cụ dụng cụ
Kế toán tài sản cố định, Công cụ dụng cụKế toán tài sản cố định, Công cụ dụng cụ
Kế toán tài sản cố định, Công cụ dụng cụ
 
Leadership Insights From TED 2016: Dream
Leadership Insights From TED 2016: DreamLeadership Insights From TED 2016: Dream
Leadership Insights From TED 2016: Dream
 
Location Reece
Location ReeceLocation Reece
Location Reece
 
Evaluation Question 2
Evaluation Question 2Evaluation Question 2
Evaluation Question 2
 
Roderik van Zeist
Roderik van Zeist Roderik van Zeist
Roderik van Zeist
 
MEMÓRIAS DAS MINHAS PRIMEIRAS EXPERIÊNCIAS COMO DOCENTE DE MÚSICA NO ENSINO R...
MEMÓRIAS DAS MINHAS PRIMEIRAS EXPERIÊNCIAS COMO DOCENTE DE MÚSICA NO ENSINO R...MEMÓRIAS DAS MINHAS PRIMEIRAS EXPERIÊNCIAS COMO DOCENTE DE MÚSICA NO ENSINO R...
MEMÓRIAS DAS MINHAS PRIMEIRAS EXPERIÊNCIAS COMO DOCENTE DE MÚSICA NO ENSINO R...
 
El incienso de_la_alabanza
El incienso de_la_alabanzaEl incienso de_la_alabanza
El incienso de_la_alabanza
 
Lakshmana
LakshmanaLakshmana
Lakshmana
 
Bloque 1:Caracteristicas internas y externas textos funcionales
Bloque 1:Caracteristicas internas y externas textos funcionalesBloque 1:Caracteristicas internas y externas textos funcionales
Bloque 1:Caracteristicas internas y externas textos funcionales
 
Opponeringen
OpponeringenOpponeringen
Opponeringen
 
Stressed02
Stressed02Stressed02
Stressed02
 
Teresa beatriz rodríguez aldeamayor
Teresa beatriz rodríguez  aldeamayorTeresa beatriz rodríguez  aldeamayor
Teresa beatriz rodríguez aldeamayor
 

Semelhante a Lucene 全文检索实践

Nginx+常见应用技术指南
Nginx+常见应用技术指南Nginx+常见应用技术指南
Nginx+常见应用技术指南
andy54321
 
Servlet & JSP 教學手冊第二版試讀 - 撰寫與設定 Servlet
Servlet & JSP 教學手冊第二版試讀 - 撰寫與設定 ServletServlet & JSP 教學手冊第二版試讀 - 撰寫與設定 Servlet
Servlet & JSP 教學手冊第二版試讀 - 撰寫與設定 Servlet
Justin Lin
 
Erlang Practice
Erlang PracticeErlang Practice
Erlang Practice
litaocheng
 
X64服务器 lamp服务器部署标准 new
X64服务器 lamp服务器部署标准 newX64服务器 lamp服务器部署标准 new
X64服务器 lamp服务器部署标准 new
Yiwei Ma
 
Javascript autoload
Javascript autoloadJavascript autoload
Javascript autoload
jay li
 
J2ee面试知识
J2ee面试知识J2ee面试知识
J2ee面试知识
yiditushe
 
Install Oracle11g For Aix 5 L
Install Oracle11g For Aix 5 LInstall Oracle11g For Aix 5 L
Install Oracle11g For Aix 5 L
heima911
 
康盛创想项目部Linux 服务器部署标准(最新版)
康盛创想项目部Linux 服务器部署标准(最新版)康盛创想项目部Linux 服务器部署标准(最新版)
康盛创想项目部Linux 服务器部署标准(最新版)
Yiwei Ma
 
配置Oracle 10g 双向流复制
配置Oracle 10g 双向流复制配置Oracle 10g 双向流复制
配置Oracle 10g 双向流复制
maclean liu
 
C语言benchmark覆盖信息收集总结4
C语言benchmark覆盖信息收集总结4C语言benchmark覆盖信息收集总结4
C语言benchmark覆盖信息收集总结4
Tao He
 

Semelhante a Lucene 全文检索实践 (20)

test
testtest
test
 
Nginx+常见应用技术指南
Nginx+常见应用技术指南Nginx+常见应用技术指南
Nginx+常见应用技术指南
 
Servlet & JSP 教學手冊第二版試讀 - 撰寫與設定 Servlet
Servlet & JSP 教學手冊第二版試讀 - 撰寫與設定 ServletServlet & JSP 教學手冊第二版試讀 - 撰寫與設定 Servlet
Servlet & JSP 教學手冊第二版試讀 - 撰寫與設定 Servlet
 
千呼萬喚始出來的Java SE 7
千呼萬喚始出來的Java SE 7千呼萬喚始出來的Java SE 7
千呼萬喚始出來的Java SE 7
 
Erlang Practice
Erlang PracticeErlang Practice
Erlang Practice
 
X64服务器 lamp服务器部署标准 new
X64服务器 lamp服务器部署标准 newX64服务器 lamp服务器部署标准 new
X64服务器 lamp服务器部署标准 new
 
啟動 Laravel 與環境設定
啟動 Laravel 與環境設定啟動 Laravel 與環境設定
啟動 Laravel 與環境設定
 
Javascript autoload
Javascript autoloadJavascript autoload
Javascript autoload
 
J2ee面试知识
J2ee面试知识J2ee面试知识
J2ee面试知识
 
Php
PhpPhp
Php
 
Oraliux+mysql5单机多实例安装文档
Oraliux+mysql5单机多实例安装文档Oraliux+mysql5单机多实例安装文档
Oraliux+mysql5单机多实例安装文档
 
2, OCP - installing and creating a database
2, OCP - installing and creating a database2, OCP - installing and creating a database
2, OCP - installing and creating a database
 
Install Oracle11g For Aix 5 L
Install Oracle11g For Aix 5 LInstall Oracle11g For Aix 5 L
Install Oracle11g For Aix 5 L
 
康盛创想项目部Linux 服务器部署标准(最新版)
康盛创想项目部Linux 服务器部署标准(最新版)康盛创想项目部Linux 服务器部署标准(最新版)
康盛创想项目部Linux 服务器部署标准(最新版)
 
配置Oracle 10g 双向流复制
配置Oracle 10g 双向流复制配置Oracle 10g 双向流复制
配置Oracle 10g 双向流复制
 
2023-netconf-deploy-azure-function-with-KEDA-on-aks
2023-netconf-deploy-azure-function-with-KEDA-on-aks2023-netconf-deploy-azure-function-with-KEDA-on-aks
2023-netconf-deploy-azure-function-with-KEDA-on-aks
 
运维自动化
运维自动化运维自动化
运维自动化
 
C语言benchmark覆盖信息收集总结4
C语言benchmark覆盖信息收集总结4C语言benchmark覆盖信息收集总结4
C语言benchmark覆盖信息收集总结4
 
用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services
 
gnutool
gnutoolgnutool
gnutool
 

Mais de yiditushe

Spring入门纲要
Spring入门纲要Spring入门纲要
Spring入门纲要
yiditushe
 
J Bpm4 1中文用户手册
J Bpm4 1中文用户手册J Bpm4 1中文用户手册
J Bpm4 1中文用户手册
yiditushe
 
性能测试实践2
性能测试实践2性能测试实践2
性能测试实践2
yiditushe
 
性能测试实践1
性能测试实践1性能测试实践1
性能测试实践1
yiditushe
 
性能测试技术
性能测试技术性能测试技术
性能测试技术
yiditushe
 
Load runner测试技术
Load runner测试技术Load runner测试技术
Load runner测试技术
yiditushe
 
J2 ee性能测试
J2 ee性能测试J2 ee性能测试
J2 ee性能测试
yiditushe
 
面向对象的Js培训
面向对象的Js培训面向对象的Js培训
面向对象的Js培训
yiditushe
 
Flex3中文教程
Flex3中文教程Flex3中文教程
Flex3中文教程
yiditushe
 
开放源代码的全文检索Lucene
开放源代码的全文检索Lucene开放源代码的全文检索Lucene
开放源代码的全文检索Lucene
yiditushe
 
基于分词索引的全文检索技术介绍
基于分词索引的全文检索技术介绍基于分词索引的全文检索技术介绍
基于分词索引的全文检索技术介绍
yiditushe
 
Lucene In Action
Lucene In ActionLucene In Action
Lucene In Action
yiditushe
 
Lucene2 4学习笔记1
Lucene2 4学习笔记1Lucene2 4学习笔记1
Lucene2 4学习笔记1
yiditushe
 
Lucene2 4 Demo
Lucene2 4 DemoLucene2 4 Demo
Lucene2 4 Demo
yiditushe
 
Lucene 3[1] 0 原理与代码分析
Lucene 3[1] 0 原理与代码分析Lucene 3[1] 0 原理与代码分析
Lucene 3[1] 0 原理与代码分析
yiditushe
 
7 面向对象设计原则
7 面向对象设计原则7 面向对象设计原则
7 面向对象设计原则
yiditushe
 
10 团队开发
10  团队开发10  团队开发
10 团队开发
yiditushe
 
9 对象持久化与数据建模
9  对象持久化与数据建模9  对象持久化与数据建模
9 对象持久化与数据建模
yiditushe
 
8 Uml构架建模
8  Uml构架建模8  Uml构架建模
8 Uml构架建模
yiditushe
 
6 架构设计
6  架构设计6  架构设计
6 架构设计
yiditushe
 

Mais de yiditushe (20)

Spring入门纲要
Spring入门纲要Spring入门纲要
Spring入门纲要
 
J Bpm4 1中文用户手册
J Bpm4 1中文用户手册J Bpm4 1中文用户手册
J Bpm4 1中文用户手册
 
性能测试实践2
性能测试实践2性能测试实践2
性能测试实践2
 
性能测试实践1
性能测试实践1性能测试实践1
性能测试实践1
 
性能测试技术
性能测试技术性能测试技术
性能测试技术
 
Load runner测试技术
Load runner测试技术Load runner测试技术
Load runner测试技术
 
J2 ee性能测试
J2 ee性能测试J2 ee性能测试
J2 ee性能测试
 
面向对象的Js培训
面向对象的Js培训面向对象的Js培训
面向对象的Js培训
 
Flex3中文教程
Flex3中文教程Flex3中文教程
Flex3中文教程
 
开放源代码的全文检索Lucene
开放源代码的全文检索Lucene开放源代码的全文检索Lucene
开放源代码的全文检索Lucene
 
基于分词索引的全文检索技术介绍
基于分词索引的全文检索技术介绍基于分词索引的全文检索技术介绍
基于分词索引的全文检索技术介绍
 
Lucene In Action
Lucene In ActionLucene In Action
Lucene In Action
 
Lucene2 4学习笔记1
Lucene2 4学习笔记1Lucene2 4学习笔记1
Lucene2 4学习笔记1
 
Lucene2 4 Demo
Lucene2 4 DemoLucene2 4 Demo
Lucene2 4 Demo
 
Lucene 3[1] 0 原理与代码分析
Lucene 3[1] 0 原理与代码分析Lucene 3[1] 0 原理与代码分析
Lucene 3[1] 0 原理与代码分析
 
7 面向对象设计原则
7 面向对象设计原则7 面向对象设计原则
7 面向对象设计原则
 
10 团队开发
10  团队开发10  团队开发
10 团队开发
 
9 对象持久化与数据建模
9  对象持久化与数据建模9  对象持久化与数据建模
9 对象持久化与数据建模
 
8 Uml构架建模
8  Uml构架建模8  Uml构架建模
8 Uml构架建模
 
6 架构设计
6  架构设计6  架构设计
6 架构设计
 

Lucene 全文检索实践

  • 1. Lucene 全文检索实践(1) 页码,1/12 Lucene 全文检索实践(1) Lucene 是 Apache Jakarta 的一个子项目,是一个全文检索的搜索引擎库。其提供了简单实用的 API,通过这些 API,可以自行编写对文件(TEXT/XML/HTML等)、目录、数据库的全文检索程序。 Features: * 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 实践任务: 1) 编写 Java 程序 MyIndexer.java,使用 JDBC 取出 MySQL 数据表内容(以某一论坛数据做测试),然后通过 org.apache.lucene.index.IndexWriter 创建索引。 2) 编写 Java 程序 MySearcher.java,通过 org.apache.lucene.search.IndexSearcher 等查询索引。 3) 实现支持中文查询及检索关键字高亮显示。 4) 通过 PHP / Java Integration 实现对 MySearch.java 的调用。 5) 实现对 PHP 手册(简体中文) 的全文检索。 Lucene 全文检索实践(2) Java 的程序基本编写完成,实现了对中文的支持。下一步是将其放到 WEB 上运行,首先想到的是使用 JSP,安装了 Apache Tomcat/4.1.24,默认的发布端口是 8080。现在面临的一个问题是:Apache httpd 的端口是 80,并且 我的机器对外只能通过 80 端口进行访问,如果将 Tomcat 的发布端口改成 80 的话,httpd 就没法对外了,而其上的 PHP 程序也将无法在 80 端口运行。 对于这个问题,我想到两种方案: 1、使用 PHP 直接调用 Java。需要做的工作是使用 --with-java 重新编译 PHP; 2、使用 mod_jk 做桥接的方式,将 servlet 引擎结合到 httpd 中。需要做的工作是编译 jakarta-tomcat- connectors-jk-1.2.5-src,生成 mod_jk.so 给 httpd 使用,然后按照 Howto 文档 进行 Tomcat、httpd 的配 置。 对于第一个方案的尝试:使用 PHP 直接调用 Java 环境 * PHP 4.3.6 prefix=/usr * Apache 1.3.27 prefix=/usr/local/apache * j2sdk1.4.1_01 prefix=/usr/local/jdk http://www.lucene.com.cn/sj.htm 2009-9-3
  • 2. Lucene 全文检索实践(1) 页码,2/12 配置步骤 1) 安装 JDK,这个就不多说了,到 GOOGLE 可以搜索出这方面的大量文章。 2) 重新编译 PHP,我的 PHP 版本是 4.3.6: cd php-4.3.6 ./configure --with-java=/usr/local/jdk make make install 完成之后,会在 PHP 的 lib 下(我的是在 /usr/lib/php)有个 php_java.jar,同时在扩展动态库存放的目录下(我的 是在 /usr/lib/php/20020429)有个 java.so 文件。到这一步需要注意一个问题,有些 PHP 版本生成的是 libphp_java.so 文件,extension 的加载只认 libphp_java.so,直接加载 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 所以如果生成的是 java.so,需要创建一个符号连接: ln -s java.so libphp_java.so 3) 修改 Apache Service 启动文件(我的这个文件为 /etc/init.d/httpd),在这个文件中加入: export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/jdk/jre/lib/i386/server:/usr/local/jdk/jre/lib 正如你所看到的,我的 JDK 装在 /usr/local/jdk 目录下,如果你的不是在此目录,请做相应改动(下同)。 4) 修改 PHP 配置文件 php.ini,找到 [Java] 部分进行修改: [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 及 java.library.path 都注释掉了,PHP 会自动认为 java.library=/usr/local/jdk/jre/lib/i386/libjava.so。 5) 重新启动 Apache httpd 服务: service httpd restart http://www.lucene.com.cn/sj.htm 2009-9-3
  • 3. Lucene 全文检索实践(1) 页码,3/12 测试 测试脚本 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 />'; ?> 总结 安装配置还算简单,但是在 PHP 运行 Java 的速度感觉较慢,所以下定决心开始实践第二个方案。(待续) Lucene 全文检索实践(3) 今天总算有些空闲时间,正好说说第二种方案:使用 mod_jk 做桥接的方式,将 servlet 引擎结合到 httpd 中。 环境 * 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 与 Tomcat,这些安装步骤就不多说了。 2) 编译 jakarta-tomcat-connectors-jk-1.2.5-src,生成 mod_jk.so,并将其复制到 apache 的 modules 存放目 录: 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 配置文件 /usr/local/apache/conf/httpd.conf,加入: LoadModule jk_module libexec/mod_jk.so AddModule mod_jk.c 这个 LoadModule 语句最好放在其他 LoadModule 语句后边。 同时在配置文件后边加入: # workers.properties 文件所在路径,后边将对此文件进行讲解 JkWorkersFile /usr/local/apache/conf/workers.properties # jk 的日志文件存放路径 JkLogFile /usr/local/apache/log/mod_jk.log http://www.lucene.com.cn/sj.htm 2009-9-3
  • 4. Lucene 全文检索实践(1) 页码,4/12 # 设置 jk 的日志级别 [debug/error/info] JkLogLevel info # 选择日志时间格式 JkLogStampFormat "[%a %b %d %H:%M:%S %Y] " # JkOptions 选项设置 JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories # JkRequestLogFormat 设置日志的请求格式 JkRequestLogFormat "%w %V %T" # 映射 /examples/* 到 worker1,worker1 在 workers.properties 文件中定义 JkMount /examples/* worker1 4) 在 /usr/local/apache/conf/ 目录下创建 workers.properties 文件,其内容如下: # 定义使用 ajp13 的 worker1 worker.list=worker1 # 设置 worker1 的属性(ajp13) 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) 好了,启动 Tomcat,重启一下 Apache HTTPD Server,访问:http://localhost/examples/index.jsp,看看结 果如何,和 http://localhost:8080/examples/index.jsp 是一样的。 提示:如果不想让别人通过 8080 端口访问到你的 Tomcat,可以将 /usr/lcoal/tomcat/conf/server.xml 配置文件中 的如下代码加上注释: <!-- <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 即可。 总结 此方案安装配置稍微复杂些,但执行效率要比第一种方案要好很多。所以决定使用这种方案来完成我的 Lucene 全文检索 实践任务。 http://www.lucene.com.cn/sj.htm 2009-9-3
  • 5. Lucene 全文检索实践(1) 页码,5/12 Tomcat Service 脚本 在 Linux (我用的是 Redhat)中,如果经常需要启动/关闭 Tomcat 的话,还是创建一个 daemon 来得比较方便,创 建步骤如下: 1) 在 /etc/init.d/ 目录下创建文件 tomcat,代码如下: # chkconfig: 345 91 10 # description: Tomcat daemon. # # 包含函数库 . /etc/rc.d/init.d/functions # 获取网络配置 . /etc/sysconfig/network # 检测 NETWORKING 是否为 "yes" [ "${NETWORKING}" = "no" ] && exit 0 # 设置变量 # $TOMCAT 指向 Tomcat 的安装目录 TOMCAT=/usr/local/tomcat # $STARTUP 指向 Tomcat 的启动脚本 STARTUP=$TOMCAT/bin/startup.sh # $SHUTDOWN 指向 Tomcat 的关闭脚本 SHUTDOWN=$TOMCAT/bin/shutdown.sh # 设置 JAVA_HOME 环境变量,指向 JDK 安装目录 export JAVA_HOME=/usr/local/jdk # 启动服务函数 start() { echo -n $"Starting Tomcat service: " $STARTUP RETVAL=$? echo } # 关闭服务函数 stop() { action $"Stopping Tomcat service: " $SHUTDOWN RETVAL=$? echo http://www.lucene.com.cn/sj.htm 2009-9-3
  • 6. Lucene 全文检索实践(1) 页码,6/12 } # 根据参数选择调用 case "$1" in start) start ;; stop) stop ;; restart) stop start ;; *) echo $"Usage: $0 start|stop|restart" exit 1 esac exit 0 2) 修改 tomcat 文件的属性 chown a+x tomcat 3) 生成 service chkconfig --add tomcat 好了,现在可以通过 service tomcat start 命令启动 Tomcat 了,关闭及重启服务的命令也类似,只是将 start 换成 stop 或 restart。 Lucene 全文检索实践(4) 在几天的研究中,了解了 Lucene 全文检索的一些原理,同时进行了实践,编写了一个论坛的全文检索创建索引程序及用 于搜索的 JSP 程序,另外还写了一个 PHP 手册(简体中文)的全文检索,可以进行多关键字搜索。基本完成了最初定下 的实践任务。 Lucene 全文检索实践(5) 对于 Lucene 的初步研究已经过去一段时间,自己感觉还不是很深入,但由于时间的关系,一直也没再拿起。应网友的要 求,将自己实践中写的一些代码贴出来,希望能对大家有用。程序没有做进一步的优化,只是很简单的实现功能而已,仅供 参考。 在实践中,我以将 PHP 中文手册中的 HTML 文件生成索引,然后通过一个 JSP 对其进行全文检索。 生成索引的 Java 代码: /** * PHPDocIndexer.java * 用于对 PHPDoc 的 HTML 页面生成索引文件。 http://www.lucene.com.cn/sj.htm 2009-9-3
  • 7. Lucene 全文检索实践(1) 页码,7/12 */ 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); //索引保存目录,必须存在 indexDocs(writer, new File("/home/nio/phpdoc-zh")); //HTML 文件保存目录 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])); http://www.lucene.com.cn/sj.htm 2009-9-3
  • 8. Lucene 全文检索实践(1) 页码,8/12 } //end for } else if (file.getPath().endsWith(".html")) { //只对 HTML 文件做索引 System.out.print("Add file:" + file + " ...."); // Add html file .... Document doc = new Document(); doc.add(Field.UnIndexed("file", file.getName())); //索引文件名 doc.add(Field.UnIndexed("modified", DateFormat.getDateTimeInstance().format (new Date(file.lastModified())))); //索引最后修改时间 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.jsp)的代码: <%@ 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, http://www.lucene.com.cn/sj.htm 2009-9-3
  • 9. Lucene 全文检索实践(1) 页码,9/12 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 简体中文手册全文检索</title> <base target="main"><!-- 由于使用了 Frame,所以指定 target 到 main 窗口显示 --> <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 { http://www.lucene.com.cn/sj.htm 2009-9-3
  • 10. Lucene 全文检索实践(1) 页码,10/12 byte[] keyValByte = request.getParameter("key").getBytes("ISO8859_1"); //查找关键字 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">提示:可使用多个关键字(使用空格隔开)提高搜索的准确率。</font> </form> <script language="JavaScript"> document.frm.key.focus(); </script> </div> <% if (keyVal != null && keyVal.length() > 0) { try { curPage = Integer.parseInt(pageVal); //将当前页转换成整数 } catch (Exception e) { //do nothing; } //end try try { Date startTime = new Date(); keyVal = keyVal.toLowerCase().replaceAll("(or|and)", "").trim().replaceAll ("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 http://www.lucene.com.cn/sj.htm 2009-9-3
  • 11. Lucene 全文检索实践(1) 页码,11/12 //总页数 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; //起始、终止下标 offset = (curPage - 1) * ROWS; int end = Math.min(hits.length(), offset + ROWS); //循环输出查询结果 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"> 检索总共耗时 <b><%=((endTime.getTime() - startTime.getTime()) / 1000.0)% ></b> 秒,约有 <b><%=hits.length()%></b> 项符合条件的记录,共 <b><%=pages%></b> 页 <% if (curPage > 1 && pages > 1) { %> | <a href="javascript:gotoPage(<%=(curPage-1)%>);" target="_self">上一页</a> <% } //end if if (curPage < pages && pages > 1) { %> | <a href="javascript:gotoPage(<%=(curPage+1)%>)" target="_self">下一页</a> http://www.lucene.com.cn/sj.htm 2009-9-3
  • 12. Lucene 全文检索实践(1) 页码,12/12 <% } //end if } catch (Exception e) { %> <!-- <%=e.getClass()%> 导致错误:<%=e.getMessage()%> --> <% } //end if } //end if %> </body> </html> 在线示例:PHP 手册(简体中文)。 http://www.lucene.com.cn/sj.htm 2009-9-3