lucene中文分詞組件(詞典全切分算法)下載

          下載地址:
          http://groups-beta.google.com/group/SegWord/web/IKAnalyzer.jar

          IKAnalyzer基于lucene2.0版本API開發(fā),實現(xiàn)了以詞典分詞為基礎(chǔ)的正反向全切分算法,是Lucene Analyzer接口的實現(xiàn),代碼使用例子如下:

          import org.mira.lucene.analysis.IK_CAnalyzer <------- 引用類
          import .....

          public class IKAnalyzerTest extends TestCase {

          RAMDirectory directory;
          private IndexSearcher searcher;

          public void setUp() throws Exception {

          directory = new RAMDirectory();

           

          IndexWriter writer = new IndexWriter(directory,
          new IK_CAnalyzer(), <------- 實例化類
          true);

          Document doc = new Document();
          doc.add(Field.Keyword("partnum", "Q36"));
          doc.add(Field.Text("description", "Illidium Space Modulator"));
          writer.addDocument(doc);
          writer.close();
          searcher = new IndexSearcher(directory);

          }

          public void testTermQuery() throws Exception {
          Query query = new TermQuery(new Term("partnum", "Q36"));
          Hits hits = searcher.search(query);
          assertEquals(1, hits.length());
          }
          }

          分詞效果測試,命令行如下:
          java -classpath IKAnalyzer.jar;lucene-core-2.0.0.jar org.mira.lucene.analysis.IK_CAnalyzer 中華人民共和國香港特別行政區(qū)


          該算法適合與互聯(lián)網(wǎng)用戶的搜索習(xí)慣和企業(yè)知識庫檢索,用戶可以用句子中涵蓋的中文詞匯搜索,如用“人民”搜索含“人民幣”的文章,這是大部分用戶的搜索思維;
          不適合用于知識挖掘和網(wǎng)絡(luò)爬蟲技術(shù),全切分法容易造成知識歧義,因為在語義學(xué)上“人民”和“人民幣”是完全搭不上關(guān)系的。

          分詞效果:

          1.實現(xiàn)中文單詞細(xì)粒度全切分

          如:中華人民共和國
          0 - 2 = 中華
          0 - 4 = 中華人民
          0 - 7 = 中華人民共和國
          1 - 3 = 華人
          2 - 4 = 人民
          2 - 7 = 人民共和國
          4 - 6 = 共和
          4 - 7 = 共和國

          2.實現(xiàn)對專有名詞的識別和切分(人名,公司名)

          如:陳文平是開睿動力通訊科技有限公司董事長
          0 - 3 = 陳文平 <------ 人名,非漢語詞匯
          4 - 6 = 開睿 <------ 公司名,非漢語詞匯
          6 - 8 = 動力
          8 - 10 = 通訊
          10 - 12 = 科技
          12 - 14 = 有限
          12 - 16 = 有限公司
          14 - 16 = 公司
          16 - 18 = 董事
          16 - 19 = 董事長
          18 - 19 = 長

          3.對數(shù)詞和量詞的合理切分

          如:據(jù)路透社報道,印度尼西亞社會事務(wù)部一官員星期二(29日)表示,日惹市附近當(dāng)?shù)貢r間27日晨5時53分發(fā)生的里氏6.2級地震已經(jīng)造成至少5427人死亡,20000余人受傷,近20萬人無家可歸。
          0 - 1 = 據(jù)
          1 - 4 = 路透社
          4 - 6 = 報道
          。。。。。。
          18 - 20 = 官員
          20 - 22 = 星期
          20 - 23 = 星期二
          22 - 23 = 二
          24 - 26 = 29
          24 - 27 = 29日
          26 - 27 = 日
          28 - 30 = 表示
          31 - 33 = 日惹
          33 - 34 = 市
          。。。。。。
          40 - 42 = 27
          40 - 43 = 27日
          43 - 44 = 晨
          44 - 45 = 5
          44 - 46 = 5時
          45 - 46 = 時
          46 - 48 = 53
          46 - 49 = 53分
          48 - 50 = 分發(fā)
          。。。。。。
          52 - 54 = 里氏
          54 - 57 = 6.2
          54 - 58 = 6.2級
          57 - 58 = 級
          58 - 60 = 地震
          。。。。。。
          66 - 70 = 5427
          66 - 71 = 5427人
          71 - 73 = 死亡
          72 - 73 = 亡
          74 - 79 = 20000
          79 - 81 = 余人
          81 - 83 = 受傷
          84 - 85 = 近
          85 - 87 = 20
          85 - 89 = 20萬人
          87 - 89 = 萬人
          89 - 93 = 無家可歸

          轉(zhuǎn)載于 http://www.jdon.com/jivejdon/thread/30255.html

          posted @ 2008-06-06 14:10 魯勝迪 閱讀(1115) | 評論 (0)編輯 收藏

          關(guān)于無刷新顯示實時數(shù)據(jù)庫程序問題

          現(xiàn)在實現(xiàn)的效果是,可以用1.jsp頁面調(diào)用2.jsp頁面,但是問題在于1.jsp頁面只能調(diào)用編譯后的2.jsp
          就是說,當(dāng)我改變數(shù)據(jù)庫中相應(yīng)內(nèi)容的值以后,它就不能實現(xiàn)做出相應(yīng)的改變了。
          但是當(dāng)我將1.jsp和2.jsp運行時,這個問題就解決了,因為在2.jsp實現(xiàn)了自動刷新功能,它可以定時的去獲取數(shù)據(jù)庫的值。

          拋出問題:那是否可以在同一頁面中導(dǎo)入兩張jsp頁面,然后實現(xiàn)一個通過刷新實現(xiàn)對另一個不刷新頁面的更新呢?



          客戶端頁面代碼(1.jsp)如下

          <html>
           <head>
           <script language="javascript">
           
                   var xmlHttp;

                   function createXMLHttpRequest(){
                      if (window.ActiveXObject){
                           xmlHttp = new ActiveXObject('Microsoft.XMLHTTP');
                      }else if(window.XMLHttpRequest){
                           xmlHttp = new XMLHttpRequest();
                      }
                  }

             function re(){
                      createXMLHttpRequest();      
                      xmlHttp.open("GET","2.jsp",true);
                      xmlHttp.onreadystatechange = callBack;
                      xmlHttp.send(null);
                    }
            
             function callBack(){
                      if (xmlHttp.readyState == 4) {
                       if (xmlHttp.status == 200) {
                          var str = xmlHttp.responseText;
                t.innerHTML=str;
                         setTimeout('re()',1000);
                              }
                        }
                   }

          </script>
          </head>
          <body onload="javascript:re();">
          <span id=t>123</span>
          </body>

          _____________________________________

          服務(wù)器端代碼(2.jsp)如下

          <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
          <jsp:directive.page import="java.sql.ResultSet"/>

          <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
          <html>
           <meta http-equiv="Refresh" content="10">
            <jsp:useBean id="db"  scope="session" class="news.sql_data"/>
          <body>

          <%
           String sql="select * from hzt_task t where title='lsd' ";
            
           ResultSet rs=db.executeQuery(sql);
            
           //int i=0;
            
           while(rs.next()){

           // runpercent=rs.getString("runpercent");
               out.println(rs.getString("runpercent"));
            
           // i++;
           }
           %>
          </body>
          </html>

          posted @ 2008-06-02 15:56 魯勝迪 閱讀(1038) | 評論 (1)編輯 收藏

          javascript傳值給jsp 簡單實例

          <body>
          <div id='aa'>
          sdfdsfdsf
          <input name="" type="button" onclick="aa();"/>
          </div>
          <script language="javascript">
           function aa(){
            document.getElementById('aa').innerHTML='123123';
           }
          </script>
          </body>

          posted @ 2008-05-19 15:16 魯勝迪 閱讀(4496) | 評論 (4)編輯 收藏

          oracle數(shù)據(jù)庫的備份與還原(本地及遠(yuǎn)程操作)

               摘要: 備份,在開始運行中CMD
          exp ay_user/ay@zhf file=e:\名稱.dmp log=e:\log.txt full=y

          //ay_user 用戶名 zhf 密碼 要備份的數(shù)據(jù)庫名和地址,log=e:\log.txt 備份生成的日志文件的地址和名稱。full=y完全備份

          還原,在開始運行中CMD
          imp zhf/huifeng@zhf file=f:\名稱.dmp log=f:\log.txt full=y   閱讀全文

          posted @ 2008-05-11 10:27 魯勝迪 閱讀(5310) | 評論 (0)編輯 收藏

          動態(tài)顯示進度條


          可以將下邊的代碼嵌入到html,jsp,asp,php或aspx文件中!


          截圖


          代碼如下:

          <body>
          <input type="button" value="start" onclick="processBar.changeMode();if(processBar.isMoving){this.value='Stop';}else{this.value='Start';}">
          </body>

          <script>
          if(window.ActiveXObject) document.execCommand("BackgroundImageCache",false,true);

          function ProcessBar(){
              this.width = 256;
              this.height = 18;
              this.top = 0;
              this.left = 0;
              this.backImg = "process_back.gif";
              this.foreImg = "process.gif";
              this.backDiv = document.createElement("div");
              this.foreDiv = document.createElement("div");
              this.fontDiv = document.createElement("div");

              this.isMoving = false;
              this.nowLength = 0;
              this.moveInterval = 100;
              this.moveRange = 1;
              this.timer;

              ProcessBar.nowObj = this;

              this.init = function(){
                   this.foreDiv.style.backgroundImage = "url(" + this.foreImg + ")";
                   this.foreDiv.style.backgroundRepeat = "no-repeat";
                   this.foreDiv.style.position = "absolute";
                   this.foreDiv.style.width = this.nowLength;
                   this.foreDiv.style.height = this.height;
                   this.foreDiv.style.top = 0;
                   this.foreDiv.style.left = 0;
                 
                   this.fontDiv.style.background = "transparent";
                   this.fontDiv.style.position = "absolute";
                   this.fontDiv.style.width = this.width;
                   this.fontDiv.style.height = this.height;
                   this.fontDiv.style.top = 2;
                   this.fontDiv.style.left = 0;
                   this.fontDiv.style.textAlign = "center";
                   this.fontDiv.style.fontSize = "13px";
                   this.fontDiv.appendChild(document.createTextNode(" "));

                   this.backDiv.style.backgroundImage = "url(" + this.backImg + ")";
                   this.backDiv.style.backgroundRepeat = "no-repeat";
                   this.backDiv.style.position = "absolute";
                   this.backDiv.style.width = this.width;
                   this.backDiv.style.height = this.height;
                   this.backDiv.style.top = this.top;
                   this.backDiv.style.left = this.left;

                   this.backDiv.appendChild(this.foreDiv);
                   this.backDiv.appendChild(this.fontDiv);

                   document.body.appendChild(this.backDiv);
              }

              this.changeMode = function(){
                   this.isMoving = !this.isMoving;
                 
                   if(this.isMoving){
                       this.timer = window.setInterval(ProcessBar.nowObj.moving, this.moveInterval);
                   }else{
                       window.clearInterval(this.timer);
                   }
              }

              this.moving = function(){
                   ProcessBar.nowObj.nowLength += ProcessBar.nowObj.moveRange;
                   ProcessBar.nowObj.foreDiv.style.width = ProcessBar.nowObj.nowLength;

                   ProcessBar.nowObj.fontDiv.firstChild.data = Math.ceil((ProcessBar.nowObj.nowLength/ProcessBar.nowObj.width )*100) + "%";

                   if(ProcessBar.nowObj.nowLength >= ProcessBar.nowObj.width ){
                       window.clearInterval(ProcessBar.nowObj.timer);
                       ProcessBar.nowObj.fontDiv.firstChild.data = "Complete!";
                   }
              }

            
          }

          var processBar = new ProcessBar();
          processBar.backImg = "http://screenprint2007.cpp114.com/UserFiles/20070412155452218.gif";
          processBar.foreImg = "http://screenprint2007.cpp114.com/UserFiles/20070412155424937.gif";
          processBar.top = 100;
          processBar.left = 20;
          processBar.init();
          </script>

          posted @ 2008-05-10 09:34 魯勝迪 閱讀(427) | 評論 (0)編輯 收藏

          oracle創(chuàng)建表空間,創(chuàng)建用戶以及授權(quán)

          //創(chuàng)建臨時表空間

          create temporary tablespace test_temp
          tempfile 'E:\oracle\product\10.2.0\oradata\testserver\test_temp01.dbf'
          size 32m
          autoextend on
          next 32m maxsize 2048m
          extent management local;

          //創(chuàng)建數(shù)據(jù)表空間
          create tablespace test_data
          logging
          datafile 'E:\oracle\product\10.2.0\oradata\testserver\test_data01.dbf'
          size 32m
          autoextend on
          next 32m maxsize 2048m
          extent management local;

          //創(chuàng)建用戶并指定表空間
          create user testserver_user identified by testserver_user
          default tablespace test_data
          temporary tablespace test_temp;

          //給用戶授予權(quán)限

          grant connect,resource to testserver_user;

          //以后以該用戶登錄,創(chuàng)建的任何數(shù)據(jù)庫對象都屬于test_temp 和test_data表空間,這就不用在每創(chuàng)建一個對象給其指定表空間了。

          posted @ 2008-05-09 20:15 魯勝迪 閱讀(21092) | 評論 (12)編輯 收藏

          遠(yuǎn)程操作、遠(yuǎn)程協(xié)助

          在使用電腦的過程中,我們會遇到各種各樣的問題。在那些自己不能獨立解決的問題面前,我們只能求助于專業(yè)的技術(shù)人員或者找經(jīng)驗豐富的朋友幫忙。可是技術(shù)人員不可能時時都在身邊,那還有沒有其他辦法可以得到技術(shù)人員的協(xié)助呢?

            微軟早就為我們在Windows XP中內(nèi)置了一個通過網(wǎng)絡(luò)的遠(yuǎn)程協(xié)助工具:“遠(yuǎn)程桌面連接”。通過遠(yuǎn)程桌面連接我們可以控制其他安裝了Windows XP、Windows 2000或者Windows Server 2003的計算機。在客戶計算機上選擇:開始|所有程序|附件|通信|遠(yuǎn)程桌面連接,在彈出的對話框中輸入你要遠(yuǎn)程連接的計算機的IP地址(如圖1所示)。如果對方允許你連接的話,就可以控制對方系統(tǒng),就好像你正坐在對方的計算機前操作對方計算機的鍵盤和鼠標(biāo)一樣。

           

          圖1 連接遠(yuǎn)程桌面

            相對的,我們也可以設(shè)置Windows XP使得其他人可以遠(yuǎn)程控制我們的計算機。在“我的電腦”上點擊右鍵,選擇“屬性”然后在彈出的對話框中選擇“遠(yuǎn)程”,然后選中“遠(yuǎn)程桌面”(如圖所示),之后選擇“選擇遠(yuǎn)程用戶”在其中輸入可以訪問的用戶名。這樣其他用戶就可以遠(yuǎn)程控制你的計算機,以便可以遠(yuǎn)程幫你解決問題。

           

          圖2 開啟遠(yuǎn)程桌面

            Windows XP中的遠(yuǎn)程連接允許我們可以從技術(shù)人員和朋友那里得到遠(yuǎn)程協(xié)助,這些用戶可以在你允許的時間內(nèi)遠(yuǎn)程控制你的計算機,并且他們的一切動作都是在你的監(jiān)視之下的。當(dāng)然為了得到遠(yuǎn)程協(xié)助你還需要在網(wǎng)絡(luò)防火墻中開放3389端口。

          posted @ 2008-05-05 15:12 魯勝迪 閱讀(273) | 評論 (0)編輯 收藏

          oracle 自增變量設(shè)置

          將表t_uaer的字段ID設(shè)置為自增:(用序列sequence的方法來實現(xiàn))

          ----創(chuàng)建表
          Create  table  t_user(
          Id number(6),userid varchar2(20),loginpassword varchar2(20),isdisable number(6)
          );

          ----創(chuàng)建序列
          create sequence user_seq
          increment by 1 
          start with 1
          nomaxvalue
          nominvalue
          nocache

          ----創(chuàng)建觸發(fā)器
          create or  replace trigger tr_user
          before insert on t_user
          for each row
          begin
          select user_seq.nextval into :new.id from dual;
          end;

          ----測試
          insert into t_user(userid,loginpassword, isdisable)
          values('ffll','liudddyujj', 0);
          insert into t_user(userid,loginpassword, isdisable)
          values('dddd','zhang', 0)
          select * from t_user;
          就可以看出結(jié)果。

          ***********************************************************************
          對sequence說明:
          increment by :用于指定序列增量(默認(rèn)值:1),如果指定的是正整數(shù),則序列號自動遞增,如果指定的是負(fù)數(shù),則自動遞減。
          start with :用于指定序列生成器生成的第一個序列號,當(dāng)序列號順序遞增時默認(rèn)值為序列號的最小值 當(dāng)序列號順序遞減時默認(rèn)值為序列號的最大值。
          Maxvalue:用于指定序列生成器可以生成的組大序列號(必須大于或等于start with,并且必須大于minvalue),默認(rèn)為nomaxvalue。
          Minvalue:用于指定序列生成器可以生成的最小序列號(必須小于或等于starr with,并且必須小于maxvalue),默認(rèn)值為nominvalue。
          Cycle:用于指定在達(dá)到序列的最大值或最小值之后是否繼續(xù)生成序列號,默認(rèn)為nocycle。
          Cache:用于指定在內(nèi)存中可以預(yù)分配的序列號個數(shù)(默認(rèn)值:20)。
          在sequence中應(yīng)注意:
          1、 第一次NEXTVAL返回的是初始值;隨后的NEXTVAL會自動增加你定義的INCREMENT BY值,然后返回增加后的值。CURRVAL 總是返回當(dāng)前SEQUENCE的值,但是在第一次NEXTVAL初始化之后才能使用CURRVAL,否則會出錯。一次NEXTVAL會增加一次SEQUENCE的值,所以如果你在同一個語句里面使用多個NEXTVAL,其值就是不一樣的。
          2、 如果指定CACHE值,ORACLE就可以預(yù)先在內(nèi)存里面放置一些sequence,這樣存取的快些。cache里面的取完后,oracle自動再取一組到cache。 使用cache或許會跳號, 比如數(shù)據(jù)庫突然不正常down掉(shutdown abort),cache中的sequence就會丟失. 所以可以在create sequence的時候用nocache防止這種情況。


          關(guān)鍵字:自增    sequence序列    increment    start with

          posted @ 2008-04-14 13:13 魯勝迪 閱讀(3241) | 評論 (0)編輯 收藏

          Lucene:基于Java的全文檢索引擎簡介【轉(zhuǎn)】

          http://www.chedong.com/tech/lucene.html



          Lucene是一個基于Java的全文索引工具包。

          1. 基于Java的全文索引引擎Lucene簡介:關(guān)于作者和Lucene的歷史
          2. 全文檢索的實現(xiàn):Luene全文索引和數(shù)據(jù)庫索引的比較
          3. 中文切分詞機制簡介:基于詞庫和自動切分詞算法的比較
          4. 具體的安裝和使用簡介:系統(tǒng)結(jié)構(gòu)介紹和演示
          5. Hacking Lucene:簡化的查詢分析器,刪除的實現(xiàn),定制的排序,應(yīng)用接口的擴展
          6. 從Lucene我們還可以學(xué)到什么

          基于Java的全文索引/檢索引擎——Lucene

          Lucene不是一個完整的全文索引應(yīng)用,而是是一個用Java寫的全文索引引擎工具包,它可以方便的嵌入到各種應(yīng)用中實現(xiàn)針對應(yīng)用的全文索引/檢索功能。

          Lucene的作者:Lucene的貢獻(xiàn)者Doug Cutting是一位資深全文索引/檢索專家,曾經(jīng)是V-Twin搜索引擎(Apple的Copland操作系統(tǒng)的成就之一)的主要開發(fā)者,后在Excite擔(dān)任高級系統(tǒng)架構(gòu)設(shè)計師,目前從事于一些INTERNET底層架構(gòu)的研究。他貢獻(xiàn)出的Lucene的目標(biāo)是為各種中小型應(yīng)用程序加入全文檢索功能。

          Lucene的發(fā)展歷程:早先發(fā)布在作者自己的www.lucene.com,后來發(fā)布在SourceForge,2001年年底成為APACHE基金會jakarta的一個子項目:http://jakarta.apache.org/lucene/

          已經(jīng)有很多Java項目都使用了Lucene作為其后臺的全文索引引擎,比較著名的有:

          • Jive:WEB論壇系統(tǒng);
          • Eyebrows:郵件列表HTML歸檔/瀏覽/查詢系統(tǒng),本文的主要參考文檔“TheLucene search engine: Powerful, flexible, and free”作者就是EyeBrows系統(tǒng)的主要開發(fā)者之一,而EyeBrows已經(jīng)成為目前APACHE項目的主要郵件列表歸檔系統(tǒng)。
          • Cocoon:基于XML的web發(fā)布框架,全文檢索部分使用了Lucene
          • Eclipse:基于Java的開放開發(fā)平臺,幫助部分的全文索引使用了Lucene

          對于中文用戶來說,最關(guān)心的問題是其是否支持中文的全文檢索。但通過后面對于Lucene的結(jié)構(gòu)的介紹,你會了解到由于Lucene良好架構(gòu)設(shè)計,對中文的支持只需對其語言詞法分析接口進行擴展就能實現(xiàn)對中文檢索的支持。

          全文檢索的實現(xiàn)機制

          Lucene的API接口設(shè)計的比較通用,輸入輸出結(jié)構(gòu)都很像數(shù)據(jù)庫的表==>記錄==>字段,所以很多傳統(tǒng)的應(yīng)用的文件、數(shù)據(jù)庫等都可以比較方便的映射到Lucene的存儲結(jié)構(gòu)/接口中。總體上看:可以先把Lucene當(dāng)成一個支持全文索引的數(shù)據(jù)庫系統(tǒng)

          比較一下Lucene和數(shù)據(jù)庫:

          Lucene 數(shù)據(jù)庫
          索引數(shù)據(jù)源:doc(field1,field2...) doc(field1,field2...)
          \ indexer /
          _____________
          | Lucene Index|
          --------------
          / searcher \
          結(jié)果輸出:Hits(doc(field1,field2) doc(field1...))
           索引數(shù)據(jù)源:record(field1,field2...) record(field1..)
          \ SQL: insert/
          _____________
          | DB Index |
          -------------
          / SQL: select \
          結(jié)果輸出:results(record(field1,field2..) record(field1...))
          Document:一個需要進行索引的“單元”
          一個Document由多個字段組成
          Record:記錄,包含多個字段
          Field:字段 Field:字段
          Hits:查詢結(jié)果集,由匹配的Document組成 RecordSet:查詢結(jié)果集,由多個Record組成

          全文檢索 ≠ like "%keyword%"

          通常比較厚的書籍后面常常附關(guān)鍵詞索引表(比如:北京:12, 34頁,上海:3,77頁……),它能夠幫助讀者比較快地找到相關(guān)內(nèi)容的頁碼。而數(shù)據(jù)庫索引能夠大大提高查詢的速度原理也是一樣,想像一下通過書后面的索引查找的速度要比一頁一頁地翻內(nèi)容高多少倍……而索引之所以效率高,另外一個原因是它是排好序的。對于檢索系統(tǒng)來說核心是一個排序問題

          由于數(shù)據(jù)庫索引不是為全文索引設(shè)計的,因此,使用like "%keyword%"時,數(shù)據(jù)庫索引是不起作用的,在使用like查詢時,搜索過程又變成類似于一頁頁翻書的遍歷過程了,所以對于含有模糊查詢的數(shù)據(jù)庫服務(wù)來說,LIKE對性能的危害是極大的。如果是需要對多個關(guān)鍵詞進行模糊匹配:like"%keyword1%" and like "%keyword2%" ...其效率也就可想而知了。

          所以建立一個高效檢索系統(tǒng)的關(guān)鍵是建立一個類似于科技索引一樣的反向索引機制,將數(shù)據(jù)源(比如多篇文章)排序順序存儲的同時,有另外一個排好序的關(guān)鍵詞列表,用于存儲關(guān)鍵詞==>文章映射關(guān)系,利用這樣的映射關(guān)系索引:[關(guān)鍵詞==>出現(xiàn)關(guān)鍵詞的文章編號,出現(xiàn)次數(shù)(甚至包括位置:起始偏移量,結(jié)束偏移量),出現(xiàn)頻率],檢索過程就是把模糊查詢變成多個可以利用索引的精確查詢的邏輯組合的過程。從而大大提高了多關(guān)鍵詞查詢的效率,所以,全文檢索問題歸結(jié)到最后是一個排序問題。

          由此可以看出模糊查詢相對數(shù)據(jù)庫的精確查詢是一個非常不確定的問題,這也是大部分?jǐn)?shù)據(jù)庫對全文檢索支持有限的原因。Lucene最核心的特征是通過特殊的索引結(jié)構(gòu)實現(xiàn)了傳統(tǒng)數(shù)據(jù)庫不擅長的全文索引機制,并提供了擴展接口,以方便針對不同應(yīng)用的定制。

          可以通過一下表格對比一下數(shù)據(jù)庫的模糊查詢:

            Lucene全文索引引擎 數(shù)據(jù)庫
          索引 將數(shù)據(jù)源中的數(shù)據(jù)都通過全文索引一一建立反向索引 對于LIKE查詢來說,數(shù)據(jù)傳統(tǒng)的索引是根本用不上的。數(shù)據(jù)需要逐個便利記錄進行GREP式的模糊匹配,比有索引的搜索速度要有多個數(shù)量級的下降。
          匹配效果 通過詞元(term)進行匹配,通過語言分析接口的實現(xiàn),可以實現(xiàn)對中文等非英語的支持。 使用:like "%net%" 會把netherlands也匹配出來,
          多個關(guān)鍵詞的模糊匹配:使用like "%com%net%":就不能匹配詞序顛倒的xxx.net..xxx.com
          匹配度 有匹配度算法,將匹配程度(相似度)比較高的結(jié)果排在前面。 沒有匹配程度的控制:比如有記錄中net出現(xiàn)5詞和出現(xiàn)1次的,結(jié)果是一樣的。
          結(jié)果輸出 通過特別的算法,將最匹配度最高的頭100條結(jié)果輸出,結(jié)果集是緩沖式的小批量讀取的。 返回所有的結(jié)果集,在匹配條目非常多的時候(比如上萬條)需要大量的內(nèi)存存放這些臨時結(jié)果集。
          可定制性 通過不同的語言分析接口實現(xiàn),可以方便的定制出符合應(yīng)用需要的索引規(guī)則(包括對中文的支持) 沒有接口或接口復(fù)雜,無法定制
          結(jié)論 高負(fù)載的模糊查詢應(yīng)用,需要負(fù)責(zé)的模糊查詢的規(guī)則,索引的資料量比較大 使用率低,模糊匹配規(guī)則簡單或者需要模糊查詢的資料量少

          全文檢索和數(shù)據(jù)庫應(yīng)用最大的不同在于:讓最相關(guān)的頭100條結(jié)果滿足98%以上用戶的需求

          Lucene的創(chuàng)新之處:

          大部分的搜索(數(shù)據(jù)庫)引擎都是用B樹結(jié)構(gòu)來維護索引,索引的更新會導(dǎo)致大量的IO操作,Lucene在實現(xiàn)中,對此稍微有所改進:不是維護一個索引文件,而是在擴展索引的時候不斷創(chuàng)建新的索引文件,然后定期的把這些新的小索引文件合并到原先的大索引中(針對不同的更新策略,批次的大小可以調(diào)整),這樣在不影響檢索的效率的前提下,提高了索引的效率。

          Lucene和其他一些全文檢索系統(tǒng)/應(yīng)用的比較:

            Lucene 其他開源全文檢索系統(tǒng)
          增量索引和批量索引 可以進行增量的索引(Append),可以對于大量數(shù)據(jù)進行批量索引,并且接口設(shè)計用于優(yōu)化批量索引和小批量的增量索引。 很多系統(tǒng)只支持批量的索引,有時數(shù)據(jù)源有一點增加也需要重建索引。
          數(shù)據(jù)源 Lucene沒有定義具體的數(shù)據(jù)源,而是一個文檔的結(jié)構(gòu),因此可以非常靈活的適應(yīng)各種應(yīng)用(只要前端有合適的轉(zhuǎn)換器把數(shù)據(jù)源轉(zhuǎn)換成相應(yīng)結(jié)構(gòu)), 很多系統(tǒng)只針對網(wǎng)頁,缺乏其他格式文檔的靈活性。
          索引內(nèi)容抓取 Lucene的文檔是由多個字段組成的,甚至可以控制那些字段需要進行索引,那些字段不需要索引,近一步索引的字段也分為需要分詞和不需要分詞的類型:
             需要進行分詞的索引,比如:標(biāo)題,文章內(nèi)容字段
             不需要進行分詞的索引,比如:作者/日期字段
          缺乏通用性,往往將文檔整個索引了
          語言分析 通過語言分析器的不同擴展實現(xiàn):
          可以過濾掉不需要的詞:an the of 等,
          西文語法分析:將jumps jumped jumper都?xì)w結(jié)成jump進行索引/檢索
          非英文支持:對亞洲語言,阿拉伯語言的索引支持
          缺乏通用接口實現(xiàn)
          查詢分析 通過查詢分析接口的實現(xiàn),可以定制自己的查詢語法規(guī)則:
          比如: 多個關(guān)鍵詞之間的 + - and or關(guān)系等
           
          并發(fā)訪問 能夠支持多用戶的使用  

           

          關(guān)于亞洲語言的的切分詞問題(Word Segment)

          對于中文來說,全文索引首先還要解決一個語言分析的問題,對于英文來說,語句中單詞之間是天然通過空格分開的,但亞洲語言的中日韓文語句中的字是一個字挨一個,所有,首先要把語句中按“詞”進行索引的話,這個詞如何切分出來就是一個很大的問題。

          首先,肯定不能用單個字符作(si-gram)為索引單元,否則查“上海”時,不能讓含有“海上”也匹配。

          但一句話:“北京天安門”,計算機如何按照中文的語言習(xí)慣進行切分呢?
          “北京 天安門” 還是“北 京 天安門”?讓計算機能夠按照語言習(xí)慣進行切分,往往需要機器有一個比較豐富的詞庫才能夠比較準(zhǔn)確的識別出語句中的單詞。

          另外一個解決的辦法是采用自動切分算法:將單詞按照2元語法(bigram)方式切分出來,比如:
          "北京天安門" ==> "北京 京天 天安 安門"。

          這樣,在查詢的時候,無論是查詢"北京" 還是查詢"天安門",將查詢詞組按同樣的規(guī)則進行切分:"北京","天安安門",多個關(guān)鍵詞之間按與"and"的關(guān)系組合,同樣能夠正確地映射到相應(yīng)的索引中。這種方式對于其他亞洲語言:韓文,日文都是通用的。

          基于自動切分的最大優(yōu)點是沒有詞表維護成本,實現(xiàn)簡單,缺點是索引效率低,但對于中小型應(yīng)用來說,基于2元語法的切分還是夠用的。基于2元切分后的索引一般大小和源文件差不多,而對于英文,索引文件一般只有原文件的30%-40%不同,


          自動切分 詞表切分
          實現(xiàn) 實現(xiàn)非常簡單 實現(xiàn)復(fù)雜
          查詢 增加了查詢分析的復(fù)雜程度, 適于實現(xiàn)比較復(fù)雜的查詢語法規(guī)則
          存儲效率 索引冗余大,索引幾乎和原文一樣大 索引效率高,為原文大小的30%左右
          維護成本 無詞表維護成本 詞表維護成本非常高:中日韓等語言需要分別維護。
          還需要包括詞頻統(tǒng)計等內(nèi)容
          適用領(lǐng)域 嵌入式系統(tǒng):運行環(huán)境資源有限
          分布式系統(tǒng):無詞表同步問題
          多語言環(huán)境:無詞表維護成本
          對查詢和存儲效率要求高的專業(yè)搜索引擎

          目前比較大的搜索引擎的語言分析算法一般是基于以上2個機制的結(jié)合。關(guān)于中文的語言分析算法,大家可以在Google查關(guān)鍵詞"wordsegment search"能找到更多相關(guān)的資料。

          安裝和使用

          下載:http://jakarta.apache.org/lucene/

          注意:Lucene中的一些比較復(fù)雜的詞法分析是用JavaCC生成的(JavaCC:JavaCompilerCompiler,純Java的詞法分析生成器),所以如果從源代碼編譯或需要修改其中的QueryParser、定制自己的詞法分析器,還需要從https://javacc.dev.java.net/下載javacc。

          lucene的組成結(jié)構(gòu):對于外部應(yīng)用來說索引模塊(index)和檢索模塊(search)是主要的外部應(yīng)用入口

          org.apache.Lucene.search/ 搜索入口
          org.apache.Lucene.index/ 索引入口
          org.apache.Lucene.analysis/ 語言分析器
          org.apache.Lucene.queryParser/ 查詢分析器
          org.apache.Lucene.document/ 存儲結(jié)構(gòu)
          org.apache.Lucene.store/  底層IO/存儲結(jié)構(gòu)
          org.apache.Lucene.util/ 一些公用的數(shù)據(jù)結(jié)構(gòu)

          簡單的例子演示一下Lucene的使用方法:

          索引過程:從命令行讀取文件名(多個),將文件分路徑(path字段)和內(nèi)容(body字段)2個字段進行存儲,并對內(nèi)容進行全文索引:索引的單位是Document對象,每個Document對象包含多個字段Field對象,針對不同的字段屬性和數(shù)據(jù)輸出的需求,對字段還可以選擇不同的索引/存儲字段規(guī)則,列表如下:
          方法 切詞 索引 存儲 用途
          Field.Text(String name, String value) Yes Yes Yes 切分詞索引并存儲,比如:標(biāo)題,內(nèi)容字段
          Field.Text(String name, Reader value) Yes Yes No 切分詞索引不存儲,比如:META信息,
          不用于返回顯示,但需要進行檢索內(nèi)容
          Field.Keyword(String name, String value) No Yes Yes 不切分索引并存儲,比如:日期字段
          Field.UnIndexed(String name, String value) No No Yes 不索引,只存儲,比如:文件路徑
          Field.UnStored(String name, String value) Yes Yes No 只全文索引,不存儲
          public class IndexFiles { 
          //使用方法:: IndexFiles [索引輸出目錄] [索引的文件列表] ...
          public static void main(String[] args) throws Exception {
          String indexPath = args[0];
          IndexWriter writer;
          //用指定的語言分析器構(gòu)造一個新的寫索引器(第3個參數(shù)表示是否為追加索引)
          writer = new IndexWriter(indexPath, new SimpleAnalyzer(), false);

          for (int i=1; i<args.length; i++) {
          System.out.println("Indexing file " + args[i]);
          InputStream is = new FileInputStream(args[i]);

          //構(gòu)造包含2個字段Field的Document對象
          //一個是路徑path字段,不索引,只存儲
          //一個是內(nèi)容body字段,進行全文索引,并存儲
          Document doc = new Document();
          doc.add(Field.UnIndexed("path", args[i]));
          doc.add(Field.Text("body", (Reader) new InputStreamReader(is)));
          //將文檔寫入索引
          writer.addDocument(doc);
          is.close();
          };
          //關(guān)閉寫索引器
          writer.close();
          }
          }
           

          索引過程中可以看到:

          • 語言分析器提供了抽象的接口,因此語言分析(Analyser)是可以定制的,雖然lucene缺省提供了2個比較通用的分析器SimpleAnalyser和StandardAnalyser,這2個分析器缺省都不支持中文,所以要加入對中文語言的切分規(guī)則,需要修改這2個分析器。
          • Lucene并沒有規(guī)定數(shù)據(jù)源的格式,而只提供了一個通用的結(jié)構(gòu)(Document對象)來接受索引的輸入,因此輸入的數(shù)據(jù)源可以是:數(shù)據(jù)庫,WORD文檔,PDF文檔,HTML文檔……只要能夠設(shè)計相應(yīng)的解析轉(zhuǎn)換器將數(shù)據(jù)源構(gòu)造成成Docuement對象即可進行索引。
          • 對于大批量的數(shù)據(jù)索引,還可以通過調(diào)整IndexerWrite的文件合并頻率屬性(mergeFactor)來提高批量索引的效率。

          檢索過程和結(jié)果顯示:

          搜索結(jié)果返回的是Hits對象,可以通過它再訪問Document==>Field中的內(nèi)容。

          假設(shè)根據(jù)body字段進行全文檢索,可以將查詢結(jié)果的path字段和相應(yīng)查詢的匹配度(score)打印出來,

          public class Search { 
          public static void main(String[] args) throws Exception {
          String indexPath = args[0], queryString = args[1];
          //指向索引目錄的搜索器
          Searcher searcher = new IndexSearcher(indexPath);
          //查詢解析器:使用和索引同樣的語言分析器
          Query query = QueryParser.parse(queryString, "body",
          new SimpleAnalyzer());
          //搜索結(jié)果使用Hits存儲
          Hits hits = searcher.search(query);
          //通過hits可以訪問到相應(yīng)字段的數(shù)據(jù)和查詢的匹配度
          for (int i=0; i<hits.length(); i++) {
          System.out.println(hits.doc(i).get("path") + "; Score: " +
          hits.score(i));
          };
          }
          }
          在整個檢索過程中,語言分析器,查詢分析器,甚至搜索器(Searcher)都是提供了抽象的接口,可以根據(jù)需要進行定制。

          Hacking Lucene

          簡化的查詢分析器

          個人感覺lucene成為JAKARTA項目后,畫在了太多的時間用于調(diào)試日趨復(fù)雜QueryParser,而其中大部分是大多數(shù)用戶并不很熟悉的,目前LUCENE支持的語法:

          Query ::= ( Clause )*
          Clause ::= ["+", "-"] [<TERM> ":"] ( <TERM> | "(" Query ")")

          中間的邏輯包括:and or + - &&||等符號,而且還有"短語查詢"和針對西文的前綴/模糊查詢等,個人感覺對于一般應(yīng)用來說,這些功能有一些華而不實,其實能夠?qū)崿F(xiàn)目前類似于Google的查詢語句分析功能其實對于大多數(shù)用戶來說已經(jīng)夠了。所以,Lucene早期版本的QueryParser仍是比較好的選擇。

          添加修改刪除指定記錄(Document)

          Lucene提供了索引的擴展機制,因此索引的動態(tài)擴展應(yīng)該是沒有問題的,而指定記錄的修改也似乎只能通過記錄的刪除,然后重新加入實現(xiàn)。如何刪除指定的記錄呢?刪除的方法也很簡單,只是需要在索引時根據(jù)數(shù)據(jù)源中的記錄ID專門另建索引,然后利用IndexReader.delete(Termterm)方法通過這個記錄ID刪除相應(yīng)的Document。

          根據(jù)某個字段值的排序功能

          lucene缺省是按照自己的相關(guān)度算法(score)進行結(jié)果排序的,但能夠根據(jù)其他字段進行結(jié)果排序是一個在LUCENE的開發(fā)郵件列表中經(jīng)常提到的問題,很多原先基于數(shù)據(jù)庫應(yīng)用都需要除了基于匹配度(score)以外的排序功能。而從全文檢索的原理我們可以了解到,任何不基于索引的搜索過程效率都會導(dǎo)致效率非常的低,如果基于其他字段的排序需要在搜索過程中訪問存儲字段,速度回大大降低,因此非常是不可取的。

          但這里也有一個折中的解決方法:在搜索過程中能夠影響排序結(jié)果的只有索引中已經(jīng)存儲的docID和score這2個參數(shù),所以,基于score以外的排序,其實可以通過將數(shù)據(jù)源預(yù)先排好序,然后根據(jù)docID進行排序來實現(xiàn)。這樣就避免了在LUCENE搜索結(jié)果外對結(jié)果再次進行排序和在搜索過程中訪問不在索引中的某個字段值。

          這里需要修改的是IndexSearcher中的HitCollector過程:

          ...
           scorer.score(new HitCollector() {
          private float minScore = 0.0f;
          public final void collect(int doc, float score) {
          if (score > 0.0f && // ignore zeroed buckets
          (bits==null || bits.get(doc))) { // skip docs not in bits
          totalHits[0]++;
          if (score >= minScore) {
          /* 原先:Lucene將docID和相應(yīng)的匹配度score例入結(jié)果命中列表中:
          * hq.put(new ScoreDoc(doc, score)); // update hit queue
          * 如果用doc 或 1/doc 代替 score,就實現(xiàn)了根據(jù)docID順排或逆排
          * 假設(shè)數(shù)據(jù)源索引時已經(jīng)按照某個字段排好了序,而結(jié)果根據(jù)docID排序也就實現(xiàn)了
          * 針對某個字段的排序,甚至可以實現(xiàn)更復(fù)雜的score和docID的擬合。
          */
          hq.put(new ScoreDoc(doc, (float) 1/doc ));
          if (hq.size() > nDocs) { // if hit queue overfull
          hq.pop(); // remove lowest in hit queue
          minScore = ((ScoreDoc)hq.top()).score; // reset minScore
          }
          }
          }
          }
          }, reader.maxDoc());

          更通用的輸入輸出接口

          雖然lucene沒有定義一個確定的輸入文檔格式,但越來越多的人想到使用一個標(biāo)準(zhǔn)的中間格式作為Lucene的數(shù)據(jù)導(dǎo)入接口,然后其他數(shù)據(jù),比如PDF只需要通過解析器轉(zhuǎn)換成標(biāo)準(zhǔn)的中間格式就可以進行數(shù)據(jù)索引了。這個中間格式主要以XML為主,類似實現(xiàn)已經(jīng)不下4,5個:

          數(shù)據(jù)源: WORD       PDF     HTML    DB       other
          \ | | | /
          XML中間格式
          |
          Lucene INDEX

          目前還沒有針對MSWord文檔的解析器,因為Word文檔和基于ASCII的RTF文檔不同,需要使用COM對象機制解析。這個是我在Google上查的相關(guān)資料:http://www.intrinsyc.com/products/enterprise_applications.asp
          另外一個辦法就是把Word文檔轉(zhuǎn)換成text:http://www.winfield.demon.nl/index.html


          索引過程優(yōu)化

          索引一般分2種情況,一種是小批量的索引擴展,一種是大批量的索引重建。在索引過程中,并不是每次新的DOC加入進去索引都重新進行一次索引文件的寫入操作(文件I/O是一件非常消耗資源的事情)。

          Lucene先在內(nèi)存中進行索引操作,并根據(jù)一定的批量進行文件的寫入。這個批次的間隔越大,文件的寫入次數(shù)越少,但占用內(nèi)存會很多。反之占用內(nèi)存少,但文件IO操作頻繁,索引速度會很慢。在IndexWriter中有一個MERGE_FACTOR參數(shù)可以幫助你在構(gòu)造索引器后根據(jù)應(yīng)用環(huán)境的情況充分利用內(nèi)存減少文件的操作。根據(jù)我的使用經(jīng)驗:缺省Indexer是每20條記錄索引后寫入一次,每將MERGE_FACTOR增加50倍,索引速度可以提高1倍左右。

          搜索過程優(yōu)化

          lucene支持內(nèi)存索引:這樣的搜索比基于文件的I/O有數(shù)量級的速度提升。
          http://www.onjava.com/lpt/a/3273
          而盡可能減少IndexSearcher的創(chuàng)建和對搜索結(jié)果的前臺的緩存也是必要的。

          Lucene面向全文檢索的優(yōu)化在于首次索引檢索后,并不把所有的記錄(Document)具體內(nèi)容讀取出來,而起只將所有結(jié)果中匹配度最高的頭100條結(jié)果(TopDocs)的ID放到結(jié)果集緩存中并返回,這里可以比較一下數(shù)據(jù)庫檢索:如果是一個10,000條的數(shù)據(jù)庫檢索結(jié)果集,數(shù)據(jù)庫是一定要把所有記錄內(nèi)容都取得以后再開始返回給應(yīng)用結(jié)果集的。所以即使檢索匹配總數(shù)很多,Lucene的結(jié)果集占用的內(nèi)存空間也不會很多。對于一般的模糊檢索應(yīng)用是用不到這么多的結(jié)果的,頭100條已經(jīng)可以滿足90%以上的檢索需求。

          如果首批緩存結(jié)果數(shù)用完后還要讀取更后面的結(jié)果時Searcher會再次檢索并生成一個上次的搜索緩存數(shù)大1倍的緩存,并再重新向后抓取。所以如果構(gòu)造一個Searcher去查1-120條結(jié)果,Searcher其實是進行了2次搜索過程:頭100條取完后,緩存結(jié)果用完,Searcher重新檢索再構(gòu)造一個200條的結(jié)果緩存,依此類推,400條緩存,800條緩存。由于每次Searcher對象消失后,這些緩存也訪問那不到了,你有可能想將結(jié)果記錄緩存下來,緩存數(shù)盡量保證在100以下以充分利用首次的結(jié)果緩存,不讓Lucene浪費多次檢索,而且可以分級進行結(jié)果緩存。

          Lucene的另外一個特點是在收集結(jié)果的過程中將匹配度低的結(jié)果自動過濾掉了。這也是和數(shù)據(jù)庫應(yīng)用需要將搜索的結(jié)果全部返回不同之處。

          我的一些嘗試

          • 支持中文的Tokenizer:這里有2個版本,一個是通過JavaCC生成的,對CJK部分按一個字符一個TOKEN索引,另外一個是從SimpleTokenizer改寫的,對英文支持?jǐn)?shù)字和字母TOKEN,對中文按迭代索引。
          • 基于XML數(shù)據(jù)源的索引器:XMLIndexer,因此所有數(shù)據(jù)源只要能夠按照DTD轉(zhuǎn)換成指定的XML,就可以用XMLIndxer進行索引了。
          • 根據(jù)某個字段排序:按記錄索引順序排序結(jié)果的搜索器:IndexOrderSearcher,因此如果需要讓搜索結(jié)果根據(jù)某個字段排序,可以讓數(shù)據(jù)源先按某個字段排好序(比如:PriceField),這樣索引后,然后在利用這個按記錄的ID順序檢索的搜索器,結(jié)果就是相當(dāng)于是那個字段排序的結(jié)果了。

          從Lucene學(xué)到更多

          Luene的確是一個面對對象設(shè)計的典范

          • 所有的問題都通過一個額外抽象層來方便以后的擴展和重用:你可以通過重新實現(xiàn)來達(dá)到自己的目的,而對其他模塊而不需要;
          • 簡單的應(yīng)用入口Searcher, Indexer,并調(diào)用底層一系列組件協(xié)同的完成搜索任務(wù);
          • 所有的對象的任務(wù)都非常專一:比如搜索過程:QueryParser分析將查詢語句轉(zhuǎn)換成一系列的精確查詢的組合(Query),通過底層的索引讀取結(jié)構(gòu)IndexReader進行索引的讀取,并用相應(yīng)的打分器給搜索結(jié)果進行打分/排序等。所有的功能模塊原子化程度非常高,因此可以通過重新實現(xiàn)而不需要修改其他模塊。 
          • 除了靈活的應(yīng)用接口設(shè)計,Lucene還提供了一些適合大多數(shù)應(yīng)用的語言分析器實現(xiàn)(SimpleAnalyser,StandardAnalyser),這也是新用戶能夠很快上手的重要原因之一。

          這些優(yōu)點都是非常值得在以后的開發(fā)中學(xué)習(xí)借鑒的。作為一個通用工具包,Lunece的確給予了需要將全文檢索功能嵌入到應(yīng)用中的開發(fā)者很多的便利。

          此外,通過對Lucene的學(xué)習(xí)和使用,我也更深刻地理解了為什么很多數(shù)據(jù)庫優(yōu)化設(shè)計中要求,比如:

          • 盡可能對字段進行索引來提高查詢速度,但過多的索引會對數(shù)據(jù)庫表的更新操作變慢,而對結(jié)果過多的排序條件,實際上往往也是性能的殺手之一。
          • 很多商業(yè)數(shù)據(jù)庫對大批量的數(shù)據(jù)插入操作會提供一些優(yōu)化參數(shù),這個作用和索引器的merge_factor的作用是類似的,
          • 20%/80%原則:查的結(jié)果多并不等于質(zhì)量好,尤其對于返回結(jié)果集很大,如何優(yōu)化這頭幾十條結(jié)果的質(zhì)量往往才是最重要的。
          • 盡可能讓應(yīng)用從數(shù)據(jù)庫中獲得比較小的結(jié)果集,因為即使對于大型數(shù)據(jù)庫,對結(jié)果集的隨機訪問也是一個非常消耗資源的操作。

          參考資料:

          Apache: Lucene Project
          http://jakarta.apache.org/lucene/
          Lucene開發(fā)/用戶郵件列表歸檔
          Lucene-dev@jakarta.apache.org
          Lucene-user@jakarta.apache.org

          The Lucene search engine: Powerful, flexible, and free
          http://www.javaworld.com/javaworld/jw-09-2000/jw-0915-Lucene_p.html

          Lucene Tutorial
          http://www.darksleep.com/puff/lucene/lucene.html

          Notes on distributed searching with Lucene
          http://home.clara.net/markharwood/lucene/

          中文語言的切分詞
          http://www.google.com/search?sourceid=navclient&hl=zh-CN&q=chinese+word+segment

          搜索引擎工具介紹
          http://searchtools.com/

          Lucene作者Cutting的幾篇論文和專利
          http://lucene.sourceforge.net/publications.html 

          Lucene的.NET實現(xiàn):dotLucene
          http://sourceforge.net/projects/dotlucene/

          Lucene作者Cutting的另外一個項目:基于Java的搜索引擎Nutch
          http://www.nutch.org/   http://sourceforge.net/projects/nutch/

          關(guān)于基于詞表和N-Gram的切分詞比較
          http://china.nikkeibp.co.jp/cgi-bin/china/news/int/int200302100112.html

          2005-01-08 Cutting在Pisa大學(xué)做的關(guān)于Lucene的講座:非常詳細(xì)的Lucene架構(gòu)解說

          特別感謝:
          前網(wǎng)易CTO許良杰(Jack Xu)給我的指導(dǎo):是您將我?guī)肓怂阉饕孢@個行業(yè)。

          posted @ 2008-04-10 13:52 魯勝迪 閱讀(202) | 評論 (0)編輯 收藏

          lucene多字段查詢

          http://hi.baidu.com/%B3%BF%D1%F4%C2%FE%B2%BD/blog/item/9478602deaa1cd37349bf7d5.html


          我的例子就是2.0的,現(xiàn)在給你的是兩個域,你可以用n個域

          BooleanQuery typeNegativeSearch = new BooleanQuery();
          QueryParser parser = new QueryParser("contents", new Analyzer());
                          parser.setDefaultOperator(QueryParser.AND_OPERATOR);
                          query = parser.parse(queryString);
                          QueryParser parser2 = new QueryParser("adISELL", new Analyzer());  

                     
                          query2 = parser2.parse("\"2\"");  
          QueryParser parser3 = new QueryParser("adISELL", new Analyzer());              
                          query3 = parser3.parse("\"2\"");             
          QueryParser parser4 = new QueryParser("adISELL", new Analyzer());              
                          query4 = parser4.parse("\"2\"");             
          QueryParser parser4 = new QueryParser("adISELL", new Analyzer());              
                          query4 = parser4.parse("\"2\"");  
          。。。。
               QueryParser parser..n = new QueryParser("adISELL", new Analyzer());           

            
                          query..n = parser..n.parse("\"2\"");  
                          
                          typeNegativeSearch.add(query,Occur.MUST);
                          typeNegativeSearch.add(query2,Occur.MUST);
          typeNegativeSearch.add(query3,Occur.MUST);
                          typeNegativeSearch.add(query4,Occur.MUST);
          .....
          typeNegativeSearch.add(query..n,Occur.MUST);

          hits = searcher.search(typeNegativeSearch);

           

          1, 幾種span的querySpanTermQuery:檢索效果完全同TermQuery,但內(nèi)部會記錄一些位置信息

          ,供SpanQuery的其它API使用,是其它屬于SpanQuery的Query的基礎(chǔ)。
          SpanFirstQuery:查找方式為從Field的內(nèi)容起始位置開始,在一個固定的寬度內(nèi)查找所指定的

          詞條。
          SpanNearQuery:功能類似PharaseQuery。SpanNearQuery查找所匹配的不一定是短語,還有可

          能是另一個SpanQuery的查詢結(jié)果作為整體考慮,進行嵌套查詢。
          SpanOrQuery:把所有SpanQuery查詢結(jié)果綜合起來,作為檢索結(jié)果。
          SpanNotQuery:從第一個SpanQuery查詢結(jié)果中,去掉第二個SpanQuery查詢結(jié)果,作為檢索結(jié)

          果。

          2, 多條件索引關(guān)系

          BooleanClause用于表示布爾查詢子句關(guān)系的類,包括:BooleanClause.Occur.MUST,

          BooleanClause.Occur.MUST_NOT,BooleanClause.Occur.SHOULD。有以下6種組合:
          1.MUST和MUST:取得連個查詢子句的交集。
          2.MUST和MUST_NOT:表示查詢結(jié)果中不能包含MUST_NOT所對應(yīng)得查詢子句的檢索結(jié)果。
          3.MUST_NOT和MUST_NOT:無意義,檢索無結(jié)果。
          4.SHOULD與MUST、SHOULD與MUST_NOT:SHOULD與MUST連用時,無意義,結(jié)果為MUST子句的檢索

          結(jié)果。與MUST_NOT連用時,功能同MUST。
          5.SHOULD與SHOULD:表示“或”關(guān)系,最終檢索結(jié)果為所有檢索子句的并集。

          posted @ 2008-04-10 13:45 魯勝迪 閱讀(1802) | 評論 (0)編輯 收藏

          僅列出標(biāo)題
          共12頁: First 上一頁 4 5 6 7 8 9 10 11 12 下一頁 
          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          導(dǎo)航

          統(tǒng)計

          常用鏈接

          留言簿(4)

          隨筆分類

          隨筆檔案

          文章分類

          新聞分類

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 五家渠市| 宁安市| 广灵县| 泰顺县| 仁怀市| 霞浦县| 隆林| 紫金县| 巴林左旗| 图片| 方城县| 鹿泉市| 扶绥县| 依安县| 大冶市| 共和县| 光山县| 娄烦县| 界首市| 平安县| 清河县| 达州市| 饶平县| 曲麻莱县| 合水县| 龙川县| 琼海市| 普宁市| 军事| 阿荣旗| 淮北市| 崇明县| 灌南县| 云龙县| 安福县| 土默特右旗| 富顺县| 婺源县| 亚东县| 巍山| 黄浦区|