posts - 40,  comments - 7,  trackbacks - 0
           

          若人生是直線前進的,
          那么命中注定有若干的交點,
          認識注定的人,
          欣賞注定的風景...

          可人生還是有選擇的,
          那么道路也就多了些分叉口,
          錯過注定的人,
          錯過注定的風景...

          若我曾經再某個分叉路口選錯了方向卻遇到了注定的人,該感謝上蒼賜予我的福氣吧!
          可是人生又有了新的岔口,選擇有些艱難,但是面對幸福我很堅定!

          該怎么愛你

          我聽 過你的微笑
          就忘了 所有動蕩
          當我靠過你的 那雙肩膀
          也就忘了 塵土飛楊
          我只是 一棵小草
          孤單的 微不足道
          當你搬進我的小小國度
          我才相信 平凡的美好
          該怎么愛你 我才不會忘
          你的溫度 來過身旁
          就算哪一天 失去了方向
          愛過的 完整的 還在心上
          該怎么愛你 才可以盼望
          那種幸福 遠遠流長
          就怕這時間 讓我趕不上
          說一句 只一句 我曾到過天堂
          我相信最燦爛的一秒
          是守著你的眼光
          不是熱烈擁抱
          不是驚濤駭浪
          我相信最美麗的風光
          是在彼此身旁
          有另一雙肩膀
          一起慢慢變老

          posted @ 2006-12-13 14:22 Lansing 閱讀(322) | 評論 (0)編輯 收藏
          ?本文主要面向具體使用,適用于已熟悉java編程的lucene初學者。
          1. Lucene的簡介


          1.1 Lucene 歷史


          ????? org.apache.lucene包是純java語言的全文索引檢索工具包。
          ????? Lucene的作者是資深的全文索引/檢索專家,最開始發布在他本人的主頁上,2001年10月貢獻給APACHE,成為APACHE基金jakarta的一個子項目。
          ????? 目前,lucene廣泛用于全文索引/檢索的項目中。
          ????? lucene也被翻譯成C#版本,目前發展為Lucene.Net(不過最近好象有流產的消息)。


          1.2 Lucene 原理


          ?????? lucene的檢索算法屬于索引檢索,即用空間來換取時間,對需要檢索的文件、字符流進行全文索引,在檢索的時候對索引進行快速的檢索,得到檢索位置,這個位置記錄檢索詞出現的文件路徑或者某個關鍵詞。
          ?????? 在使用數據庫的項目中,不使用數據庫進行檢索的原因主要是:數據庫在非精確查詢的時候使用查詢語言“like %keyword%”,對數據庫進行查詢是對所有記錄遍歷,并對字段進行“%keyword%”匹配,在數據庫的數據龐大以及某個字段存儲的數據量龐大的時候,這種遍歷是致命的,它需要對所有的記錄進行匹配查詢。因此,lucene主要適用于文檔集的全文檢索,以及海量數據庫的模糊檢索,特別是對數據庫的xml或者大數據的字符類型。


          2.Lucene的下載和配置


          2.1 Lucene的下載


          ?????? lucene在jakarta項目中的發布主頁:http://jakarta.apache.org/lucene/docs/index.html。以下主要針對windows用戶,其它用戶請在上面的地址中查找相關下載。


          ?????? lucene的.jar包的下載(包括.jar和一個范例demo):
          http://apache.oregonstate.edu/jakarta/lucene/binaries/lucene-1.4-final.zip


          ??????? lucene的源代碼下載:
          http://www.signal42.com/mirrors/apache/jakarta/lucene/source/lucene-1.4-final-src.zip


          ?lucene的api地址:http://jakarta.apache.org/lucene/docs/api/index.html


          ?本文使用lucene版本:lucene-1.4-final.jar。


          2.2 lucene的配置


          ??????? 首先請確定你的機子已經進行了java使用環境的基本配置,即確保在某個平臺下能夠運行java源代碼,否則請查閱相關文檔進行配置。
          ??????? 接下來進入lucene的配置:
          ??????? 普通使用者:在環境變量的CLASSPATH中添加lucene的位置。比如:“D:\java \lucene-1.4-final\lucene-1.4-final.jar;”。
          ?????? jbuilder使用者:在“Project”--“Project Properties”--“Required Libraries”進行添加。
          ?????? Jsp使用者:也可以直接將lucene-1.4-final.jar文件放到\WEB-INF\classes下。


          3. Lucene 的范例(Demo )


          3.1 Demo說明

          ?????
          ??????? 可以得到的Demo包括:lucene-demos-1.4-final、XMLIndexingDemo,lucene-demos-1.4-final中包括對普通文件和html文件的兩種索引,XMLIndexingDemo針對xml文件的索引。他們的區別主要在于:對普通文件進行索引時只要對文件的全文進行索引,而針對html、xml文件時,對標簽類型不能進行索引,在實現上:html、xml的索引需要額外的數據流分析器,以分析哪些內容有用哪些無用。因此,在后兩者實現上,索引的時間額外開支,甚至超過索引本身時間,而檢索時間沒有區別。


          ??????? 以上Demo中,lucene-demos-1.4-final自帶于lucene-1.4-final.zip中,XMLIndexingDemo的下載地址:
          http://cvs.apache.org/viewcvs.cgi/jakarta-lucene-sandbox/contributions/XML-Indexing-Demo/


          3.2 Demo的運行


          ????????首先將demo.jar的路徑添加如環境變量的CLASSPATH中,例如:“D:\java\lucene-1.4-final\lucene-demos-1.4-final.jar;”,同時確保已經添加lucene-1.4-final.jar。


          ????????然后進行文件的全文索引,在dos控制臺中,輸入命令“java org.apache.lucene.demo.IndexFiles {full-path-to-lucene}/src”,后面的路徑為所要進行索引的文件夾,例如:“java org.apache.lucene.demo.IndexFiles c:\test”。


          ??????? 接著對索引進行檢索,敲入“java org.apache.lucene.demo.SearchFiles”,在提示“Query:”后輸入檢索詞,程序將進行檢索列出檢索得到的結果(檢索詞出現的文件路徑)。
          ?
          ?????? 其他Demo的運行請參考\docs\demo.html。
          ?????? 在運行Demo后請閱讀Demo的源代碼以便深入學習。

          4. 利用Lucene進行索引


          ??????? 進行lucene的熟悉后,我們將學習如何使用Lucene。
          ?一段索引的應用實例:

          ??? //需要捕捉IOException異常
          ??? //建立一個IndexWriter,索引保存目錄為“index”
          ??? String[] stopStrs = {
          ??????? "他奶奶的", "fuck"};
          ??? StandardAnalyzer analyzer = new StandardAnalyzer(stopStrs);
          ??? IndexWriter writer = new IndexWriter("index", analyzer, true);
          ???
          ??? //添加一條文檔
          ??? Document doc = new Document();
          ??? doc.add(Field.UnIndexed("id", "1"));//“id”為字段名,“1”為字段值
          ??? doc.add(Field.Text("text", "fuck,他奶奶的,入門與使用"));
          ??? writer.addDocument(doc);
          ???
          ??? //索引完成后的處理
          ??? writer.optimize();
          ??? writer.close();

          ?????? 看完這段實例后,我們開始熟悉lucene的使用:

          4.1 Lucene的索引接口


          ?在學習索引的時候,首先需要熟悉幾個接口:


          4.1.1分析器Analyzer


          ??????? 分析器主要工作是篩選,一段文檔進來以后,經過它,出去的時候只剩下那些有用的部分,其他則剔除。而這個分析器也可以自己根據需要而編寫。
          ??????? org.apache.lucene.analysis.Analyzer:這是一個虛構類,以下兩個借口均繼承它而來。


          ????????org.apache.lucene.analysis.SimpleAnalyzer:分析器,支持最簡單拉丁語言。


          ????????org.apache.lucene.analysis.standard.StandardAnalyzer:標準分析器,除了拉丁語言還支持亞洲語言,并在一些匹配功能上進行完善。在這個接口中還有一個很重要的構造函數:StandardAnalyzer(String[] stopWords),可以對分析器定義一些使用詞語,這不僅可以免除檢索一些無用信息,而且還可以在檢索中定義禁止的政治性、非法性的檢索關鍵詞。


          4.1.2 IndexWriter


          ????????IndexWriter的構造函數有三種接口,針對目錄Directory、文件File、文件路徑String三種情況。
          例如IndexWriter(String path, Analyzer a, boolean create),path為文件路徑,a為分析器,create標志是否重建索引(true:建立或者覆蓋已存在的索引,false:擴展已存在的索引。)
          ?????? 一些重要的方法:

          接口名

          備注

          addDocument(Document doc)

          索引添加一個文檔

          addIndexes(Directory[] dirs)

          將目錄中已存在索引添加到這個索引

          addIndexes(IndexReader[] readers)

          將提供的索引添加到這個索引

          optimize()

          合并索引并優化

          close()

          關閉


          ?????? IndexWriter為了減少大量的io維護操作,在每得到一定量的索引后建立新的小索引文件(筆者測試索引批量的最小單位為10),然后再定期將它們整合到一個索引文件中,因此在索引結束時必須進行wirter. optimize(),以便將所有索引合并優化。


          4.1.3 org.apache.lucene.document


          ?以下介紹兩種主要的類:
          ?a)org.apache.lucene.document.Document:
          ????????Document文檔類似數據庫中的一條記錄,可以由好幾個字段(Field)組成,并且字段可以套用不同的類型(詳細見b)。Document的幾種接口:
          ?

          接口名

          備注

          add(Field field)

          添加一個字段(Field)到Document

          String get(String name)

          從文檔中獲得一個字段對應的文本

          Field getField(String name)

          由字段名獲得字段值

          Field[] getFields(String name)

          由字段名獲得字段值的集


          ?b)org.apache.lucene.document.Field
          ??????? 即上文所說的“字段”,它是Document的片段section。
          ??????? Field的構造函數:
          ?????? Field(String name, String string, boolean store, boolean index, boolean token)。
          ??????? Indexed:如果字段是Indexed的,表示這個字段是可檢索的。
          ????????Stored:如果字段是Stored的,表示這個字段的值可以從檢索結果中得到。
          ????????Tokenized:如果一個字段是Tokenized的,表示它是有經過Analyzer轉變后成為一個tokens序列,在這個轉變過程tokenization中,Analyzer提取出需要進行索引的文本,而剔除一些冗余的詞句(例如:a,the,they等,詳見org.apache.lucene.analysis.StopAnalyzer.ENGLISH_STOP_WORDS和org.apache.lucene.analysis.standard.StandardAnalyzer(String[] stopWords)的API)。Token是索引時候的基本單元,代表一個被索引的詞,例如一個英文單詞,或者一個漢字。因此,所有包含中文的文本都必須是Tokenized的。
          ???? Field的幾種接口:

          Name

          Stored

          Indexed

          Tokenized

          use

          Keyword(String name,

          ??????? String value)

          Y

          Y

          N

          date,url

          Text(String name, Reader value)

          N

          Y

          Y

          short text fields:

          title,subject

          Text(String name, String value)

          Y

          Y

          Y

          longer text fields,

          like “body”

          UnIndexed(String name,

          String value)

          Y

          N

          N

          ?

          UnStored(String name,

          ???????? String value)

          N

          Y

          Y

          ?

          ?


          5. 利用Lucene進行檢索


          5.1 一段簡單的檢索代碼

          ?

          ??? //需要捕捉IOException,ParseException異常
          ??? //處理檢索條件
          ??? Query query = QueryParser.parse("入門", "text", analyzer);

          ??? //檢索
          ??? Searcher searcher = new IndexSearcher("./index");//"index"指定索引文件位置
          Hits hits = searcher.search(query);

          ??? //打印結果值集
          ??? for (int i = 0; i < hits.length(); i++) {
          ????? doc = hits.doc(i);
          ????? String id = doc.get("id");
          ????? System.out.println("found " + "入門" + " on the id:" + id);
          }

          ?

          5.2 利用Lucene的檢索接口


          5.2.1 Query與QueryParser


          ??????? 主要使用方法:
          QueryParser .parse(String query, String field, Analyzer analyzer),例如:
          Query query = QueryParser.parse("入門", "text", analyzer);
          "入門"為檢索詞, "text"為檢索的字段名, analyzer為分析器


          5.2.2 Hits與Searcher


          ?????? Hits的主要使用接口:
          ?

          接口名

          備注

          Doc(int n)

          返回第n個的文檔的所有字段

          length()

          返回這個集中的可用個數

          ?


          6. Lucene的其他使用


          6.1 Lucene 的索引修改


          ??????? 下面給出一段修改索引的代碼,請根據Lucene的API解讀:


          ? /**
          ?? * 對已有的索引添加新的一條索引
          ?? * @param idStr String:要修改的id
          ?? * @param doc Document:要修改的值
          ?? */
          ? public void addIndex(String idStr, String valueStr) {
          ??? StandardAnalyzer analyzer = new StandardAnalyzer();
          ??? IndexWriter writer = null;
          ??? try {
          ????? writer = new IndexWriter(indexPath, analyzer, false);
          ????? writer.mergeFactor = 2; //修正lucene 1.4.2 bug,不添加則不合并原有索引

          ?????? ?? Document doc = new Document();
          ????????? doc.add(Field.UnIndexed("id", idStr));//“id”為字段名,“1”為字段值
          ????????? doc.add(Field.Text("text", valueStr));
          ????? writer.addDocument(doc);

          ????? writer.optimize();
          ????? writer.close();
          ??? }
          ??? catch (IOException ioe) {
          ????? ioe.printStackTrace();
          ??? }
          ? }

          ? /**
          ?? * 刪除索引
          ?? *
          ?? * @param idStr String
          ?? */
          ? public void deleteIndex(String idStr) {
          ??? try {
          ????? Directory dirt = FSDirectory.getDirectory(indexPath, false);
          ????? IndexReader reader = IndexReader.open(dirt);
          ????? IndexXML.deleteIndex(idStr, reader);
          ????? reader.close();
          ????? dirt.close();
          ??? }
          ??? catch (IOException ioe) {
          ????? ioe.printStackTrace();
          ??? }
          ? }


          6.2 Lucene 的檢索結果排序


          ??????? Lucene的排序主要是對org.apache.lucene.search.Sort的使用。Sort可以直接根據字段Field生成,也可以根據標準的SortField生成,但是作為Sort的字段,必須符合以下的條件:唯一值以及Indexed。可以對Integers, Floats, Strings三種類型排序。
          ??????? 對整數型的ID檢索結果排序只要進行以下的簡單操作:

          ?Sort sort = new Sort("id");
          Hits hits = searcher.search(query, sort);

          ?????? 用戶還可以根據自己定義更加復雜的排序,詳細請參考API。


          7 總結


          ??????? Lucene給java的全文索引檢索帶來了非常強大的力量,以上僅對Lucene進行簡單的入門說明。

          posted @ 2006-11-08 14:59 Lansing 閱讀(351) | 評論 (0)編輯 收藏

          Lucene提供了方便您創建自建查詢的API,也通過QueryParser提供了強大的查詢語言。

          本文講述Lucene的查詢語句解析器支持的語法,Lucene的查詢語句解析器是使用JavaCC工

          具生成的詞法解析器,它將查詢字串解析為Lucene Query對象。
          項(Term)
          一條搜索語句被拆分為一些項(term)和操作符(operator)。項有兩種類型:單獨項和

          短語。
          單獨項就是一個單獨的單詞,例如"test" , "hello"。
          短語是一組被雙引號包圍的單詞,例如"hello dolly"。
          多個項可以用布爾操作符連接起來形成復雜的查詢語句(接下來您就會看到)。
          注意:Analyzer建立索引時使用的解析器和解析單獨項和短語時的解析器相同,因此選擇

          一個不會受查詢語句干擾的Analyzer非常重要。luence1.4的StandardAnalyzer的解析器已

          經支持中文等亞洲國家的文字了,可以直接。標準的解析其不支持中文。

          域(Field)
          Lucene支持域。您可以指定在某一個域中搜索,或者就使用默認域。域名及默認域是具體

          索引器實現決定的。(怎么定制默認域?)
          您可以這樣搜索域:域名+":"+搜索的項名。
          舉個例子,假設某一個Lucene索引包含兩個域,title和text,text是默認域。如果您想查

          找標題為"The Right Way"且含有"don't go this way"的文章,您可以輸入:
          title:"The Right Way" AND text:go
          或者
          title:"Do it right" AND right
          因為text是默認域,所以這個域名可以不行。
          注意:域名只對緊接于其后的項生效,所以
          title:Do it right
          只有"Do"屬于title域。"it"和"right"仍將在默認域中搜索(這里是text域)。

          項修飾符(Term Modifiers)
          Lucene支持項修飾符以支持更寬范圍的搜索選項。
          用通配符搜索
          Lucene支持單個與多個字符的通配搜索。
          使用符號"?"表示單個任意字符的通配。
          使用符號"*"表示多個任意字符的通配。
          單個任意字符匹配的是所有可能單個字符。例如,搜索"text或者"test",可以這樣:

          te?t
          多個任意字符匹配的是0個及更多個可能字符。例如,搜索test, tests 或者 tester,可

          以這樣: test*
          您也可以在字符竄中間使用多個任意字符通配符。 te*t
          注意:您不能在搜索的項開始使用*或者?符號。

          模糊查詢
          Lucene支持基于Levenshtein Distance與Edit Distance算法的模糊搜索。要使用模糊搜索

          只需要在單獨項的最后加上符號"~"。例如搜索拼寫類似于"roam"的項這樣寫:
          roam~
          這次搜索將找到形如foam和roams的單詞。
          注意:使用模糊查詢將自動得到增量因子(boost factor)為0.2的搜索結果.

          鄰近搜索(Proximity Searches)
          Lucene還支持查找相隔一定距離的單詞。鄰近搜索是在短語最后加上符號"~"。例如在文檔

          中搜索相隔10個單詞的"apache"和"jakarta",這樣寫: "jakarta apache"~10

          Boosting a Term
          Lucene provides the relevance level of matching documents based on the terms

          found. To boost a term use the caret, "^", symbol with a boost factor (a

          number) at the end of the term you are searching. The higher the boost factor,

          the more relevant the term will be.
          Lucene可以設置在搜索時匹配項的相似度。在項的最后加上符號"^"緊接一個數字(增量值

          ),表示搜索時的相似度。增量值越高,搜索到的項相關度越好。
          Boosting allows you to control the relevance of a document by boosting its

          term. For example, if you are searching for jakarta apache and you want the

          term "jakarta" to be more relevant boost it using the ^ symbol along with the

          boost factor next to the term. You would type:
          通過增量一個項可以控制搜索文檔時的相關度。例如如果您要搜索jakarta apache,同時

          您想讓"jakarta"的相關度更加好,那么在其后加上"^"符號和增量值,也就是您輸入:
          jakarta^4 apache
          This will make documents with the term jakarta appear more relevant. You can

          also boost Phrase Terms as in the example:
          這將使得生成的doucment盡可能與jakarta相關度高。您也可以增量短語,象以下這個例子

          一樣:
          "jakarta apache"^4 "jakarta lucene"

          By default, the boost factor is 1. Although, the boost factor must be positive,

          it can be less than 1 (i.e. .2)
          默認情況下,增量值是1。增量值也可以小于1(例如0.2),但必須是有效的。

          布爾操作符
          布爾操作符可將項通過邏輯操作連接起來。Lucene支持AND, "+", OR, NOT 和 "-"這些操

          作符。(注意:布爾操作符必須全部大寫)

          OR
          OR操作符是默認的連接操作符。這意味著如果兩個項之間沒有布爾操作符,就是使用OR操

          作符。OR操作符連接兩個項,意味著查找含有任意項的文檔。這與集合并運算相同。符號

          ||可以代替符號OR。
          搜索含有"jakarta apache" 或者 "jakarta"的文檔,可以使用這樣的查詢:
          "jakarta apache" jakarta 或者 "jakarta apache" OR jakarta

          AND
          AND操作符匹配的是兩項同時出現的文檔。這個與集合交操作相等。符號&&可以代替符號

          AND。
          搜索同時含有"jakarta apache" 與 "jakarta lucene"的文檔,使用查詢:
          "jakarta apache" AND "jakarta lucene"

          +
          "+"操作符或者稱為存在操作符,要求符號"+"后的項必須在文檔相應的域中存在。
          搜索必須含有"jakarta",可能含有"lucene"的文檔,使用查詢:
          +jakarta apache

          NOT
          NOT操作符排除那些含有NOT符號后面項的文檔。這和集合的差運算相同。符號!可以代替

          符號NOT。
          搜索含有"jakarta apache",但是不含有"jakarta lucene"的文檔,使用查詢:
          "jakarta apache" NOT "jakarta lucene"
          注意:NOT操作符不能單獨與項使用構成查詢。例如,以下的查詢查不到任何結果:
          NOT "jakarta apache"

          -
          "-"操作符或者禁止操作符排除含有"-"后面的相似項的文檔。
          搜索含有"jakarta apache",但不是"jakarta lucene",使用查詢:
          "jakarta apache" -"jakarta lucene"

          分組(Grouping)
          Lucene支持使用圓括號來組合字句形成子查詢。這對于想控制查詢布爾邏輯的人十分有用


          搜索含有"jakarta"或者"apache",同時含有"website"的文檔,使用查詢:
          (jakarta OR apache) AND website
          這樣就消除了歧義,保證website必須存在,jakarta和apache中之一也存在。
          轉義特殊字符(Escaping Special Characters)
          Lucene支持轉義特殊字符,因為特殊字符是查詢語法用到的。現在,特殊字符包括
          + - && || ! ( ) { } [ ] ^ " ~ * ? : \
          轉義特殊字符只需在字符前加上符號\,例如搜索(1+1):2,使用查詢
          \(1\+1\)\:2??
          (李宇翻譯,來自Lucene的幫助文檔)上面這段看了之后很有幫助,解除了使用中的不少

          疑惑,謝謝翻譯者,同時應該看到,有的時候詳細查看使用幫助文檔是非常有用的。
          ------------------------------------------------------------------------------
          索引文件格式

          本文定義了Lucene(版本1.3)用到的索引文件的格式。
          Jakarta Lucene是用Java寫成的,同時有很多團體正在默默的用其他的程序語言來改寫它

          。如果這些新的版本想和Jakarta Lucene兼容,就需要一個與具體語言無關的Lucene索引

          文件格式。本文正是試圖提供一個完整的與語言無關的Jakarta Lucene 1.3索引文件格式

          的規格定義。
          隨著Lucene不斷發展,本文也應該更新。不同語言寫成的Lucene實現版本應當盡力遵守文

          件格式,也必須產生本文的新版本。
          本文同時提供兼容性批注,描述文件格式上與前一版本不同的地方。

          定義
          Lucene中最基礎的概念是索引(index),文檔(document),域(field)和項(term)


          索引包含了一個文檔的序列。
          · 文檔是一些域的序列。
          · 域是一些項的序列。
          · 項就是一個字串。
          存在于不同域中的同一個字串被認為是不同的項。因此項實際是用一對字串表示的,第一

          個字串是域名,第二個是域中的字串。

          倒排索引
          為了使得基于項的搜索更有效率,索引中項是靜態存儲的。Lucene的索引屬于索引方式中

          的倒排索引,因為對于一個項這種索引可以列出包含它的文檔。這剛好是文檔與項自然聯

          系的倒置。

          域的類型
          Lucene中,域的文本可能以逐字的非倒排的方式存儲在索引中。而倒排過的域稱為被索引

          過了。域也可能同時被存儲和被索引。
          域的文本可能被分解許多項目而被索引,或者就被用作一個項目而被索引。大多數的域是

          被分解過的,但是有些時候某些標識符域被當做一個項目索引是很有用的。

          段(Segment)
          Lucene索引可能由多個子索引組成,這些子索引成為段。每一段都是完整獨立的索引,能

          被搜索。索引是這樣作成的:
          1. 為新加入的文檔創建新段。
          2. 合并已經存在的段。
          搜索時需要涉及到多個段和/或者多個索引,每一個索引又可能由一些段組成。

          文檔號(Document Number)
          內部的來說,Lucene用一個整形(interger)的文檔號來指示文檔。第一個被加入到索引

          中的文檔就是0號,順序加入的文檔將得到一個由前一個號碼遞增而來的號碼。
          注意文檔號是可能改變的,所以在Lucene外部存儲這些號碼時必須小心。特別的,號碼的

          改變的情況如下:
          · 只有段內的號碼是相同的,不同段之間不同,因而在一個比段廣泛的上下文環境中使用

          這些號碼時,就必須改變它們。標準的技術是根據每一段號碼多少為每一段分配一個段號

          。將段內文檔號轉換到段外時,加上段號。將某段外的文檔號轉換到段內時,根據每段中

          可能的轉換后號碼范圍來判斷文檔屬于那一段,并減調這一段的段號。例如有兩個含5個文

          檔的段合并,那么第一段的段號就是0,第二段段號5。第二段中的第三個文檔,在段外的

          號碼就是8。
          · 文檔刪除后,連續的號碼就出現了間斷。這可以通過合并索引來解決,段合并時刪除的

          文檔相應也刪掉了,新合并而成的段并沒有號碼間斷。

          緒論
          索引段維護著以下的信息:
          · 域集合。包含了索引中用到的所有的域。
          · 域值存儲表。每一個文檔都含有一個“屬性-值”對的列表,屬性即為域名。這個列表

          用來存儲文檔的一些附加信息,如標題,url或者訪問數據庫的一個ID。在搜索時存儲域的

          集合可以被返回。這個表以文檔號標識。
          · 項字典。這個字典含有所有文檔的所有域中使用過的的項,同時含有使用過它的文檔的

          文檔號,以及指向使用頻數信息和位置信息的指針。
          · 項頻數信息。對于項字典中的每個項,這些信息包含含有這個項的文檔的總數,以及每

          個文檔中使用的次數。
          · 項位置信息。對于項字典中的每個項,都存有在每個文檔中出現的各個位置。
          · Normalization factors. For each field in each document, a value is stored

          that is multiplied into the score for hits on that field. 標準化因子。對于文檔

          中的每一個域,存有一個值,用來以后乘以這個這個域的命中數(hits)。
          · 被刪除的文檔信息。這是一個可選文件,用來表明那些文檔已經刪除了。
          接下來的各部分部分詳細描述這些信息。

          文件的命名(File Naming)
          同屬于一個段的文件擁有相同的文件名,不同的擴展名。擴展名由以下討論的各種文件格

          式確定。
          一般來說,一個索引存放一個目錄,其所有段都存放在這個目錄里,盡管我們不要求您這

          樣做。

          基本數據類型(Primitive Types)

          Byte
          最基本的數據類型就是字節(byte,8位)。文件就是按字節順序訪問的。其它的一些數據

          類型也定義為字節的序列,文件的格式具有字節意義上的獨立性。

          UInt32
          32位無符號整數,由四個字節組成,高位優先。

          UInt32 --> <Byte>4
          Uint64
          64位無符號整數,由八字節組成,高位優先。

          UInt64 --> <Byte>8
          VInt
          可變長的正整數類型,每字節的最高位表明還剩多少字節。每字節的低七位表明整數的值

          。因此單字節的值從0到127,兩字節值從128到16,383,等等。

          VInt 編碼示例
          Value
          First byte
          Second byte
          Third byte

          0
          00000000
          1
          00000001
          2
          00000010
          ...
          127
          01111111
          128
          10000000
          00000001
          129
          10000001
          00000001
          130
          10000010
          00000001
          ...
          16,383
          11111111
          01111111
          16,384
          10000000
          10000000
          00000001
          16,385
          10000001
          10000000
          00000001
          ...

          這種編碼提供了一種在高效率解碼時壓縮數據的方法。

          Chars
          Lucene輸出UNICODE字符序列,使用標準UTF-8編碼。

          String
          Lucene輸出由VINT和字符串組成的字串,VINT表示字串長,字符串緊接其后。
          String --> VInt, Chars

          索引包含的文件(Per-Index Files)
          這部分介紹每個索引包含的文件。

          Segments文件
          索引中活動的段存儲在Segments文件中。每個索引只能含有一個這樣的文件,名

          為"segments".這個文件依次列出每個段的名字和每個段的大小。
          Segments --> SegCount, <SegName, SegSize>SegCount
          SegCount, SegSize --> UInt32
          SegName --> String
          SegName表示該segment的名字,同時作為索引其他文件的前綴。
          SegSize是段索引中含有的文檔數。

          Lock文件
          有一些文件用來表示另一個進程在使用索引。
          · 如果存在"commit.lock"文件,表示有進程在寫"segments"文件和刪除無用的段索引文

          件,或者表示有進程在讀"segments"文件和打開某些段的文件。在一個進程在讀

          取"segments"文件段信息后,還沒來得及打開所有該段的文件前,這個Lock文件可以防止

          另一個進程刪除這些文件。
          · 如果存在"index.lock"文件,表示有進程在向索引中加入文檔,或者是從索引中刪除文

          檔。這個文件防止很多文件同時修改一個索引。

          Deleteable文件
          名為"deletetable"的文件包含了索引不再使用的文件的名字,這些文件可能并沒有被實際

          的刪除。這種情況只存在與Win32平臺下,因為Win32下文件仍打開時并不能刪除。
          Deleteable --> DelableCount, <DelableName>DelableCount
          DelableCount --> UInt32
          DelableName --> String

          段包含的文件(Per-Segment Files)
          剩下的文件是每段中包含的文件,因此由后綴來區分。
          域(Field)
          域集合信息(Field Info)
          所有域名都存儲在這個文件的域集合信息中,這個文件以后綴.fnm結尾。
          FieldInfos (.fnm) --> FieldsCount, <FieldName, FieldBits>FieldsCount
          FieldsCount --> VInt
          FieldName --> String
          FieldBits --> Byte
          目前情況下,FieldBits只有使用低位,對于已索引的域值為1,對未索引的域值為0。
          文件中的域根據它們的次序編號。因此域0是文件中的第一個域,域1是接下來的,等等。

          這個和文檔號的編號方式相同。
          域值存儲表(Stored Fields)
          域值存儲表使用兩個文件表示:

          1. 域索引(.fdx文件)。
          如下,對于每個文檔這個文件包含指向域值的指針:
          FieldIndex (.fdx) --> <FieldValuesPosition>SegSize
          FieldValuesPosition --> Uint64
          FieldValuesPosition指示的是某一文檔的某域的域值在域值文件中的位置。因為域值文件

          含有定長的數據信息,因而很容易隨機訪問。在域值文件中,文檔n的域值信息就存在n*8

          位置處(The position of document n's field data is the Uint64 at n*8 in this

          file.)。

          2. 域值(.fdt文件)。
          如下,每個文檔的域值信息包含:
          FieldData (.fdt) --> <DocFieldData>SegSize
          DocFieldData --> FieldCount, <FieldNum, Bits, Value>FieldCount
          FieldCount --> VInt
          FieldNum --> VInt
          Bits --> Byte
          Value --> String
          目前情況下,Bits只有低位被使用,值為1表示域名被分解過,值為0表示未分解過。

          項字典(Term Dictionary)
          項字典用以下兩個文件表示:
          1. 項信息(.tis文件)。
          TermInfoFile (.tis)--> TermCount, TermInfos
          TermCount --> UInt32
          TermInfos --> <TermInfo>TermCount
          TermInfo --> <Term, DocFreq, FreqDelta, ProxDelta>
          Term --> <PrefixLength, Suffix, FieldNum>
          Suffix --> String
          PrefixLength, DocFreq, FreqDelta, ProxDelta
          --> VInt
          項信息按項排序。項信息排序時先按項所屬的域的文字順序排序,然后按照項的字串的文

          字順序排序。
          項的字前綴往往是共同的,與字的后綴組成字。PrefixLength變量就是表示與前一項相同

          的前綴的字數。因此,如果前一個項的字是"bone",后一個是"boy"的話,PrefixLength值

          為2,Suffix值為"y"。

          FieldNum指明了項屬于的域號,而域名存儲在.fdt文件中。
          DocFreg表示的是含有該項的文檔的數量。
          FreqDelta指明了項所屬TermFreq變量在.frq文件中的位置。詳細的說,就是指相對于前一

          個項的數據的位置偏移量(或者是0,表示文件中第一個項)。
          ProxDelta指明了項所屬的TermPosition變量在.prx文件中的位置。詳細的說,就是指相對

          于前一個項的數據的位置偏移量(或者是0,表示文件中第一個項)。

          2. 項信息索引(.tii文件)。
          每個項信息索引文件包含.tis文件中的128個條目,依照條目在.tis文件中的順序。這樣設

          計是為了一次將索引信息讀入內存能,然后使用它來隨機的訪問.tis文件。
          這個文件的結構和.tis文件非常類似,只在每個條目記錄上增加了一個變量IndexDelta。
          TermInfoIndex (.tii)--> IndexTermCount, TermIndices
          IndexTermCount --> UInt32
          TermIndices --> <TermInfo, IndexDelta>IndexTermCount
          IndexDelta --> VInt
          IndexDelta表示該項的TermInfo變量值在.tis文件中的位置。詳細的講,就是指相對于前

          一個條目的偏移量(或者是0,對于文件中第一個項)。

          項頻數(Frequencies)
          .frq文件包含每一項的文檔的列表,還有該項在對應文檔中出現的頻數。
          FreqFile (.frq) --> <TermFreqs>TermCount
          TermFreqs --> <TermFreq>DocFreq
          TermFreq --> DocDelta, Freq?
          DocDelta,Freq --> VInt
          TermFreqs序列按照項來排序(依據于.tis文件中的項,即項是隱含存在的)。
          TermFreq元組按照文檔號升序排列。
          DocDelta決定了文檔號和頻數。詳細的說,DocDelta/2表示相對于前一文檔號的偏移量(

          或者是0,表示這是TermFreqs里面的第一項)。當DocDelta是奇數時表示在該文檔中頻數

          為1,當DocDelta是偶數時,另一個VInt(Freq)就表示在該文檔中出現的頻數。
          例如,假設某一項在文檔7中出現一次,在文檔11中出現了3次,在TermFreqs中就存在如下

          的VInts序列: 15, 22, 3

          項位置(Position)
          .prx文件包含了某文檔中某項出現的位置信息的列表。
          ProxFile (.prx) --> <TermPositions>TermCount
          TermPositions --> <Positions>DocFreq
          Positions --> <PositionDelta>Freq
          PositionDelta --> VInt
          TermPositions按照項來排序(依據于.tis文件中的項,即項是隱含存在的)。
          Positions元組按照文檔號升序排列。
          PositionDelta是相對于前一個出現位置的偏移位置(或者為0,表示這是第一次在這個文

          檔中出現)。
          例如,假設某一項在某文檔第4項出現,在另一個文檔中第5項和第9項出現,將存在如下的

          VInt序列: 4, 5, 4

          標準化因子(Normalization Factor)
          .nrm文件包含了每個文檔的標準化因子,標準化因子用來以后乘以這個這個域的命中數。
          Norms (.nrm) --> <Byte>SegSize
          每個字節記錄一個浮點數。位0-2包含了3位的尾數部分,位3-8包含了5位的指數部分。
          按如下規則可將這些字節轉換為IEEE標準單精度浮點數:
          1. 如果該字節是0,就是浮點0;
          2. 否則,設置新浮點數的標志位為0;
          3. 將字節中的指數加上48后作為新的浮點數的指數;
          4. 將字節中的尾數映射到新浮點數尾數的高3位;并且
          5. 設置新浮點數尾數的低21位為0。

          被刪除的文檔(Deleted Document)
          .del文件是可選的,只有在某段中存在刪除操作后才存在:
          Deletions (.del) --> ByteCount,BitCount,Bits
          ByteSize,BitCount --> Uint32
          Bits --> <Byte>ByteCount
          ByteCount表示的是Bits列表中Byte的數量。典型的,它等于(SegSize/8)+1。
          BitCount表示Bits列表中多少個已經被設置過了。
          Bits列表包含了一些位(bit),順序表示一個文檔。當對應于文檔號的位被設置了,就標

          志著這個文檔已經被刪除了。位的順序是從低到高。因此,如果Bits包含兩個字節,0x00

          和0x02,那么表示文檔9已經刪除了。

          局限性(Limitations)
          在以上的文件格式中,好幾處都有限制項和文檔的最大個數為32位數的極限,即接近于40

          億。今天看來,這不會造成問題,但是,長遠的看,可能造成問題。因此,這些極限應該

          或者換為UInt64類型的值,或者更好的,換為VInt類型的值(VInt值沒有上限)。
          有兩處地方的代碼要求必須是定長的值,他們是:
          1. FieldValuesPosition變量(存儲于域索引文件中,.fdx文件)。它已經是一個UInt64

          型,所以不會有問題。
          2. TermCount變量(存儲于項信息文件中,.tis文件)。這是最后輸出到文件中的,但是

          最先被讀取,因此是存儲于文件的最前端 。索引代碼先在這里寫入一個0值,然后在其他

          文件輸出完畢后覆蓋這個值。所以無論它存儲在什么地方,它都必須是一個定長的值,它

          應該被變成UInt64型。
          除此之外,所有的UInt值都可以換成VInt型以去掉限制
          ------------------------------------------------------------------------------

          ---------
          下面是lucene組成結構中的類說明:
          org.apache.Lucene.search/ 搜索入口
          org.apache.Lucene.index/ 索引入口
          org.apache.Lucene.analysis/ 語言分析器
          org.apache.Lucene.queryParser/ 查詢分析器
          org.apache.Lucene.document/ 存儲結構
          org.apache.Lucene.store/? 底層IO/存儲結構
          org.apache.Lucene.util/ 一些公用的數據結構

          域存儲字段規則
          方法 切詞 索引 存儲 用途
          Field.Text(String name, String value) 切分詞索引并存儲,比如:標題,內容字段
          Field.Text(String name, Reader value)? 切分詞索引不存儲,比如:META信息,
          不用于返回顯示,但需要進行檢索內容
          Field.Keyword(String name, String value)? 不切分索引并存儲,比如:日期字段
          Field.UnIndexed(String name, String value)? 不索引,只存儲,比如:文件路徑
          Field.UnStored(String name, String value)? 只全文索引,不存儲

          建立索引的例子:
          public class IndexFiles {??
          //使用方法:: IndexFiles [索引輸出目錄] [索引的文件列表] ...??
          public static void main(String[] args) throws Exception {???
          String indexPath = args[0];??? IndexWriter writer;???
          //用指定的語言分析器構造一個新的寫索引器(第3個參數表示是否為追加索引)???

          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]);?????
          //構造包含2個字段Field的Document對象?????
          //一個是路徑path字段,不索引,只存儲?????
          //一個是內容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();??? };???
          //關閉寫索引器???
          writer.close();? }
          }
          索引過程中可以看到:

          語言分析器提供了抽象的接口,因此語言分析(Analyser)是可以定制的,雖然lucene缺省

          提供了2個比較通用的分析器SimpleAnalyser和StandardAnalyser,這2個分析器缺省都不

          支持中文,所以要加入對中文語言的切分規則,需要修改這2個分析器。
          Lucene并沒有規定數據源的格式,而只提供了一個通用的結構(Document對象)來接受索

          引的輸入,因此輸入的數據源可以是:數據庫,WORD文檔,PDF文檔,HTML文檔……只要能

          夠設計相應的解析轉換器將數據源構造成成Docuement對象即可進行索引。
          對于大批量的數據索引,還可以通過調整IndexerWrite的文件合并頻率屬性(mergeFactor

          )來提高批量索引的效率。
          檢索過程和結果顯示:

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

          假設根據body字段進行全文檢索,可以將查詢結果的path字段和相應查詢的匹配度(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());???
          //搜索結果使用Hits存儲???
          Hits hits = searcher.search(query);???
          //通過hits可以訪問到相應字段的數據和查詢的匹配度???
          for (int i=0; i<hits.length(); i++) {?????
          System.out.println(hits.doc(i).get("path") + "; Score: " +?????????????????????

          ??? hits.score(i));??? };? }
          }
          添加修改刪除指定記錄(Document)

          Lucene提供了索引的擴展機制,因此索引的動態擴展應該是沒有問題的,而指定記錄的修

          改也似乎只能通過記錄的刪除,然后重新加入實現。如何刪除指定的記錄呢?刪除的方法

          也很簡單,只是需要在索引時根據數據源中的記錄ID專門另建索引,然后利用

          IndexReader.delete(Termterm)方法通過這個記錄ID刪除相應的Document。

          根據某個字段值的排序功能
          根據某個字段值的排序功能

          lucene缺省是按照自己的相關度算法(score)進行結果排序的,但能夠根據其他字段進行

          結果排序是一個在LUCENE的開發郵件列表中經常提到的問題,很多原先基于數據庫應用都

          需要除了基于匹配度(score)以外的排序功能。而從全文檢索的原理我們可以了解到,任

          何不基于索引的搜索過程效率都會導致效率非常的低,如果基于其他字段的排序需要在搜

          索過程中訪問存儲字段,速度回大大降低,因此非常是不可取的。

          但這里也有一個折中的解決方法:在搜索過程中能夠影響排序結果的只有索引中已經存儲

          的docID和score這2個參數,所以,基于score以外的排序,其實可以通過將數據源預先排

          好序,然后根據docID進行排序來實現。這樣就避免了在LUCENE搜索結果外對結果再次進行

          排序和在搜索過程中訪問不在索引中的某個字段值。

          這里需要修改的是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和相應的匹配度score例入結果命中列表中:??????? * hq.put(new ScoreDoc

          (doc, score));?? // update hit queue?????????????? * 如果用doc 或 1/doc 代替

          score,就實現了根據docID順排或逆排?????????????? * 假設數據源索引時已經按照某個

          字段排好了序,而結果根據docID排序也就實現了?????????????? * 針對某個字段的排序

          ,甚至可以實現更復雜的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面向全文檢索的優化在于首次索引檢索后,并不把所有的記錄(Document)具體內

          容讀取出來,而起只將所有結果中匹配度最高的頭100條結果(TopDocs)的ID放到結果集

          緩存中并返回,這里可以比較一下數據庫檢索:如果是一個10,000條的數據庫檢索結果集

          ,數據庫是一定要把所有記錄內容都取得以后再開始返回給應用結果集的。所以即使檢索

          匹配總數很多,Lucene的結果集占用的內存空間也不會很多。對于一般的模糊檢索應用是

          用不到這么多的結果的,頭100條已經可以滿足90%以上的檢索需求。

          如果首批緩存結果數用完后還要讀取更后面的結果時Searcher會再次檢索并生成一個上次

          的搜索緩存數大1倍的緩存,并再重新向后抓取。所以如果構造一個Searcher去查1-120條

          結果,Searcher其實是進行了2次搜索過程:頭100條取完后,緩存結果用完,Searcher重

          新檢索再構造一個200條的結果緩存,依此類推,400條緩存,800條緩存。由于每次

          Searcher對象消失后,這些緩存也訪問那不到了,你有可能想將結果記錄緩存下來,緩存

          數盡量保證在100以下以充分利用首次的結果緩存,不讓Lucene浪費多次檢索,而且可以分

          級進行結果緩存。

          Lucene的另外一個特點是在收集結果的過程中將匹配度低的結果自動過濾掉了。這也是和

          數據庫應用需要將搜索的結果全部返回不同之處。

          posted @ 2006-11-08 14:58 Lansing 閱讀(1368) | 評論 (0)編輯 收藏

          Eclipse及其插件介紹和下載- -

          TagEclipse ?? 插件 ?? ??????????????????????????????????????

          0.Eclipse下載
          EMF,GEF - Graphical Editor Framework,UML2,VE - Visual Editor都在這里下載
          http://www.eclipse.org/downloads/index.php
          ?
          0.5.lomboz J2EE插件,開發JSP,EJB
          http://forge.objectweb.org/projects/lomboz
          1.MyEclipse J2EE開發插件,支持SERVLET/JSP/EJB/數據庫操縱等
          http://www.myeclipseide.com
          ?
          2.Properties Editor? 編輯java的屬性文件,并可以自動存盤為Unicode格式
          http://propedit.sourceforge.jp/index_en.html
          ?
          3.Colorer Take? 為上百種類型的文件按語法著色
          http://colorer.sourceforge.net/
          ?
          4.XMLBuddy 編輯xml文件
          http://www.xmlbuddy.com
          ?
          5.Code Folding? 加入多種代碼折疊功能(比eclipse自帶的更多)
          http://www.coffee-bytes.com/servlet/PlatformSupport
          ?
          6.Easy Explorer? 從eclipse中訪問選定文件、目錄所在的文件夾
          http://easystruts.sourceforge.net/
          ?
          7.Fat Jar 打包插件,可以方便的完成各種打包任務,可以包含外部的包等
          http://fjep.sourceforge.net/
          ?
          8.RegEx Test 測試正則表達式
          http://brosinski.com/stephan/archives/000028.php
          ?
          9.JasperAssistant 報表插件(強,要錢的)
          http://www.jasperassistant.com/
          ?
          10.Jigloo GUI Builder JAVA的GUI編輯插件
          http://cloudgarden.com/jigloo/
          ?
          11.Profiler 性能跟蹤、測量工具,能跟蹤、測量BS程序
          http://sourceforge.net/projects/eclipsecolorer/
          ?
          12.AdvanQas 提供對if/else等條件語句的提示和快捷幫助(自動更改結構等)
          http://eclipsecolorer.sourceforge.net/advanqas/index.html
          ?
          13.Log4E Log4j插件,提供各種和Log4j相關的任務,如為方法、類添加一個logger等
          http://log4e.jayefem.de/index.php/Main_Page
          ?
          14.VSSPlugin VSS插件
          http://sourceforge.net/projects/vssplugin
          ?
          15.Implementors 提供跳轉到一個方法的實現類,而不是接中的功能(實用!)
          http://eclipse-tools.sourceforge.net/implementors/
          ?
          16.Call Hierarchy 顯示一個方法的調用層次(被哪些方法調,調了哪些方法)
          http://eclipse-tools.sourceforge.net/call-hierarchy/index.html
          ?
          17.EclipseTidy 檢查和格式化HTML/XML文件
          http://eclipsetidy.sourceforge.net/
          ?
          18.Checkclipse 檢查代碼的風格、寫法是否符合規范
          http://www.mvmsoft.de/content/plugins/checkclipse/checkclipse.htm
          ?
          19.Hibernate Synchronizer Hibernate插件,自動映射等
          http://www.binamics.com/hibernatesync/
          ?
          20.VeloEclipse? Velocity插件
          http://propsorter.sourceforge.net/
          ?
          21.EditorList 方便的列出所有打開的Editor
          http://editorlist.sourceforge.net/
          ?
          22.MemoryManager 內存占用率的監視
          http://cloudgarden.com/memorymanager/
          ?
          23.swt-designer java的GUI插件
          http://www.swt-designer.com/
          ?
          24.TomcatPlugin 支持Tomcat插件
          http://www.sysdeo.com/eclipse/tomcatPlugin.html
          ?
          25.XML Viewer
          http://tabaquismo.freehosting.net/ignacio/eclipse/xmlview/index.html
          ?
          26.quantum 數據庫插件
          http://quantum.sourceforge.net/
          ?
          27.Dbedit 數據庫插件
          http://sourceforge.net/projects/dbedit
          ?
          28.clay.core 可視化的數據庫插件
          http://www.azzurri.jp/en/software/index.jsp
          http://www.azzurri.jp/eclipse/plugins
          ?
          29.hiberclipse hibernate插件
          http://hiberclipse.sourceforge.net
          http://www.binamics.com/hibernatesync
          ?
          30.struts-console Struts插件
          http://www.jamesholmes.com/struts/console/
          ?
          31.easystruts Struts插件
          http://easystruts.sourceforge.net
          ?
          32.veloedit Velocity插件
          http://veloedit.sourceforge.net/
          ?
          33.jalopy 代碼整理插件
          http://jalopy.sourceforge.net/
          ?
          34.JDepend 包關系分析
          http://andrei.gmxhome.de/jdepend4eclipse/links.html
          ?
          35.Spring IDE Spring插件
          http://springide-eclip.sourceforge.net/updatesite/
          ?
          36.doclipse 可以產生xdoclet 的代碼提示
          http://beust.com/doclipse/

          posted @ 2006-09-21 19:17 Lansing 閱讀(316) | 評論 (0)編輯 收藏

          Struts常見異常信息和解決方法

          以下所說的struts-config.xml和ApplicationResources.properties等文件名是缺省時使用的,如果你使用了多模塊,或指定了不同的資源文件名稱,這些名字要做相應的修改。

          1、“No bean found under attribute key XXX”
          在struts-config.xml里定義了一個ActionForm,但type屬性指定的類不存在,type屬性的值應該是Form類的全名。或者是,在Action的定義中,name或attribute屬性指定的ActionForm不存在。

          2、“Cannot find bean?XXX in any scope”
          在Action里一般會request.setAttribute()一些對象,然后在轉向的jsp文件里(用tag或request.getAttribute()方法)得到這些對象并顯示出來。這個異常是說jsp要得到一個對象,但前面的Action里并沒有將對象設置到request(也可以是session、servletContext)里。
          可能是名字錯了,請檢查jsp里的tag的一般是name屬性,或getAttribute()方法的參數值;或者是Action邏輯有問題沒有執行setAttribute()方法就先轉向了。
          還有另外一個可能,純粹是jsp文件的問題,例如<logic:iterate>會指定一個id值,然后在循環里<bean:write>使用這個值作為name的值,如果這兩個值不同,也會出現此異常。(都是一個道理,request里沒有對應的對象。)

          3、“Missing message for key "XXX"”
          缺少所需的資源,檢查ApplicationResources.properties文件里是否有jsp文件里需要的資源,例如:

          < bean:message?key = " msg.name.prompt " />

          這行代碼會找msg.name.prompt資源,如果AppliationResources.properties里沒有這個資源就會出現本異常。在使用多模塊時,要注意在模塊的struts-config-xxx.xml里指定要使用的資源文件名稱,否則當然什么資源也找不到,這也是一個很容易犯的錯誤。

          4、“No getter method for property?XXX of bean teacher”
          這條異常信息說得很明白,jsp里要取一個bean的屬性出來,但這個bean并沒有這個屬性。你應該檢查jsp中某個標簽的property屬性的值。例如下面代碼中的cade應該改為code才對:

          < bean:write?name = " teacher " ?property = " cade " ?filter = " true " />

          5、“Cannot find ActionMappings or ActionFormBeans collection”
          待解決。

          6、“Cannot retrieve mapping for action XXX”
          在.jsp的<form>標簽里指定action='/XXX',但這個Action并未在struts-config.xml里設置過。

          7、HTTP Status 404 - /xxx/xxx.jsp
          Forward的path屬性指向的jsp頁面不存在,請檢查路徑和模塊,對于同一模塊中的Action轉向,path中不應包含模塊名;模塊間轉向,記住使用contextRelative="true"。

          8、沒有任何異常信息,顯示空白頁面
          可能是Action里使用的forward與struts-config.xml里定義的forward名稱不匹配。

          9、“The element type "XXX" must be terminated by the matching end-tag "XXX".”
          這個是struts-config.xml文件的格式錯誤,仔細檢查它是否是良構的xml文件,關于xml文件的格式這里就不贅述了。

          10、“Servlet.init() for servlet action threw exception”
          一般出現這種異常在后面會顯示一個關于ActionServlet的異常堆棧信息,其中指出了異常具體出現在代碼的哪一行。我曾經遇到的一次提示如下:

          java.lang.NullPointerException
          ????at?org.apache.struts.action.ActionServlet.parseModuleConfigFile(ActionServlet.java:
          1003 )
          ????at?org.apache.struts.action.ActionServlet.initModuleConfig(ActionServlet.java:
          955 )


          為解決問題,先下載struts的源碼包,然后在ActionServlet.java的第1003行插入斷點,并對各變量進行監視。很丟人,我竟然把struts-config.xml文件弄丟了,因此出現了上面的異常,應該是和CVS同步時不小心刪除的。

          11、“Resources not defined for Validator”
          這個是利用Validator插件做驗證時可能出現的異常,這時你要檢查validation.xml文件,看里面使用的資源是否確實有定義,form的名稱是否正確,等等。

          posted @ 2006-09-19 11:34 Lansing 閱讀(338) | 評論 (0)編輯 收藏
               摘要: PowerDesigner 設計數據庫 ? ? ? ?????? 本文檔不講述如何使用 PowerDesigner ,而是講述如何將 PowerDesigner...  閱讀全文
          posted @ 2006-09-13 14:53 Lansing 閱讀(680) | 評論 (0)編輯 收藏
          Log4j由三個重要的組件構成:日志信息的優先級,日志信息的輸出目的地,日志信息的輸出格式。日志信息的優先級從高到低有ERROR、WARN、INFO、DEBUG,分別用來指定這條日志信息的重要程度;日志信息的輸出目的地指定了日志將打印到控制臺還是文件中;而輸出格式則控制了日志信息的顯示內容。

            一、定義配置文件

            其實您也可以完全不使用配置文件,而是在代碼中配置Log4j環境。但是,使用配置文件將使您的應用程序更加靈活。Log4j支持兩種配置文件格式,一種是XML格式的文件,一種是Java特性文件(鍵=值)。下面我們介紹使用Java特性文件做為配置文件的方法:

            1.配置根Logger,其語法為:

            log4j.rootLogger = [ level ] , appenderName, appenderName, …

            其中,level 是日志記錄的優先級,分為OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定義的級別。Log4j建議只使用四個級別,優先級從高到低分別是ERROR、WARN、INFO、DEBUG。通過在這里定義的級別,您可以控制到應用程序中相應級別的日志信息的開關。比如在這里定義了INFO級別,則應用程序中所有DEBUG級別的日志信息將不被打印出來。 appenderName就是指定日志信息輸出到哪個地方。您可以同時指定多個輸出目的地。

            2.配置日志信息輸出目的地Appender,其語法為:

            log4j.appender.appenderName = fully.qualified.name.of.appender.class
            log4j.appender.appenderName.option1 = value1
            …
            log4j.appender.appenderName.option = valueN

            其中,Log4j提供的appender有以下幾種:
            org.apache.log4j.ConsoleAppender(控制臺),
            org.apache.log4j.FileAppender(文件),
            org.apache.log4j.DailyRollingFileAppender(每天產生一個日志文件),
            org.apache.log4j.RollingFileAppender(文件大小到達指定尺寸的時候產生一個新的文件),
            org.apache.log4j.WriterAppender(將日志信息以流格式發送到任意指定的地方)

            3.配置日志信息的格式(布局),其語法為:

            log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
            log4j.appender.appenderName.layout.option1 = value1
            …
            log4j.appender.appenderName.layout.option = valueN

            其中,Log4j提供的layout有以下幾種:
            org.apache.log4j.HTMLLayout(以HTML表格形式布局),
            org.apache.log4j.PatternLayout(可以靈活地指定布局模式),
            org.apache.log4j.SimpleLayout(包含日志信息的級別和信息字符串),
            org.apache.log4j.TTCCLayout(包含日志產生的時間、線程、類別等等信息)

            Log4J采用類似C語言中的printf函數的打印格式格式化日志信息,打印參數如下: %m 輸出代碼中指定的消息

            %p 輸出優先級,即DEBUG,INFO,WARN,ERROR,FATAL
            %r 輸出自應用啟動到輸出該log信息耗費的毫秒數
            %c 輸出所屬的類目,通常就是所在類的全名
            %t 輸出產生該日志事件的線程名
            %n 輸出一個回車換行符,Windows平臺為“\r\n”,Unix平臺為“\n”
            %d 輸出日志時間點的日期或時間,默認格式為ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},輸出類似:2002年10月18日 22:10:28,921
            %l 輸出日志事件的發生位置,包括類目名、發生的線程,以及在代碼中的行數。舉例:Testlog4.main(TestLog4.java:10)

            二、在代碼中使用Log4j

            1.得到記錄器

            使用Log4j,第一步就是獲取日志記錄器,這個記錄器將負責控制日志信息。其語法為:

            public static Logger getLogger( String name)

            通過指定的名字獲得記錄器,如果必要的話,則為這個名字創建一個新的記錄器。Name一般取本類的名字,比如:

            static Logger logger = Logger.getLogger ( ServerWithLog4j.class.getName () )

            2.讀取配置文件

            當獲得了日志記錄器之后,第二步將配置Log4j環境,其語法為:

            BasicConfigurator.configure (): 自動快速地使用缺省Log4j環境。
            PropertyConfigurator.configure ( String configFilename) :讀取使用Java的特性文件編寫的配置文件。
            DOMConfigurator.configure ( String filename ) :讀取XML形式的配置文件。

            3.插入記錄信息(格式化日志信息)

            當上兩個必要步驟執行完畢,您就可以輕松地使用不同優先級別的日志記錄語句插入到您想記錄日志的任何地方,其語法如下:

            Logger.debug ( Object message ) ;
            Logger.info ( Object message ) ;
            Logger.warn ( Object message ) ;
            Logger.error ( Object message ) ;

          posted @ 2006-08-22 14:28 Lansing 閱讀(367) | 評論 (0)編輯 收藏
          速度瓶頸問題的提出

            在企業級的Java應用中,訪問數據庫是一個必備的環節。數據庫作為數據資源的集散地,往往位于企業級軟件體系的后方,供前方的應用程序訪問。在Java技術的體系中,應用程序是通過JDBC(Java Database Connectivity)接口來訪問數據庫的,JDBC支持"建立連接、SQL語句查詢、處理結果"等基本功能。在應用JDBC接口訪問數據庫的過程中,只要根據規范來操作,這些功能的實現不會出差錯。但是,有些時候進行數據查詢的效率著實讓開發人員懊惱不已,明明根據規范編寫的程序,卻得不到預期的運行效果,造成了整個軟件的執行效率不高。

            起初,我們把問題歸結于Java字節碼加載和執行速度的緩慢,緊接著硬件的功能普遍得到了增強,證明這樣的想法些許是錯誤的,還沒有抓到真正的根本原因。本文將逐步解剖JDBC訪問數據庫的機制,深層分析造成這種速度瓶頸問題的原因,并提出在現有的Java技術框架下解決這個速度瓶頸問題的思路和方法。

            JDBC訪問數據庫的機制

          ????????????????
          圖1????????????????????????????????????????????????圖2

            圖1和圖2描述了Java應用程序通過JDBC接口訪問數據庫的4種驅動模式,也就是底層實現JDBC接口的模式。對于這些模式,我們逐一介紹:

            模式4:圖1左邊的分支稱為模式4,它一般是數據庫廠商才能實現的純Java的基于本地協議的驅動,直接調用DBMS(數據庫管理系統)使用的網絡協議,對于企業內部互聯網來說,是一個實用的解決方案。

            模式3:圖1右邊的分支稱為模式3,它同樣是一個純Java驅動,不同于模式4的是基于網絡協議。它的機制是將JDBC調用轉換為中間網絡協議,然后轉換為DBMS協議。中間網絡協議層起到一個讀取數據庫的中間件的作用,能夠連接許多類型的數據庫,因而是最靈活的JDBC模式。這種模式的產品比較適用于企業內部互聯網,如若支持國際互聯網,還需添加對安全、穿過防火墻訪問等的支持。

            模式1:圖2左邊的分支稱為模式1,即通常由Sun公司提供的JDBC-ODBC橋接器。它提供了經由一種或多種ODBC驅動進行訪問的JDBC接口,而ODBC驅動,在很多情況下也即數據庫的客戶端,必須加載到客戶機。因而,它適用于下載和自動安裝Java程序不重要、實驗用途或者沒有其它JDBC驅動可用的情況下。

            模式2:圖2右邊的分支成為模式2,類似于JDBC-ODBC橋接器,需要加載到客戶機,卻是一個部分用Java實現的驅動接口。它將JDBC調用轉換為對數據庫(Oracle、Sybase、Informix、DB2等)客戶端接口的調用。

            不同模式的JDBC接口的選擇

            以上闡述的JDBC接口的模式不同,讓我們可以把JDBC接口按照實現的模式分為四類。有些同仁可能有這樣的體會,選擇不同的JDBC接口會有不同的訪問速度,為何會出現這樣的情況?這個問題的答案是,不同的應用需要不同模式的JDBC接口,因而我們在面對一個應用時,要慎重選擇JDBC接口。

            通常的DBMS都支持微軟提出的ODBC規范,因而模式1可當作您在設計和實現軟件時的選擇,它易于配置的特性能夠讓你把選擇JDBC等煩惱的問題暫且拋在一邊,讓自己的Java程序能夠及早地正常工作起來。

            一般說來,商業DBMS的提供者往往會為自己的數據庫提供一個JDBC接口,應用的是模式4。這種模式的優勢在于和數據庫本身結合比較緊密,而且是純Java的實現,在企業級的軟件應用中,應該是首選。例如,對于Oracle數據庫來說,有Oracle、SilverStream、DataDirect等公司提供這種類型的驅動,其性能往往被評價為最高效的、最可靠的驅動程序。但偶爾也有比較麻煩的情況,例如微軟就不會提供MS SQL的JDBC接口,這時就需要到Sun的網站(http://industry.java.sun.com/products/jdbc/drivers)查找相關的模式4驅動,上面提到的DataDirect公司(http://www.datadirect-technologies.com/jdbc/jdbc.asp)就提供了支持MS SQL的模式4驅動,只是你需要支付750$購買這個JDBC驅動。

            同樣是純Java實現的模式3,與模式4相比,優勢在于對多種數據庫的支持,體現了其靈活性。在大型的企業級的軟件應用中,后臺數據庫往往不是一個,而且是由不同的廠商支持的。不過,模式3的JDBC驅動往往提供許多企業級的特征,例如SSL安全、支持分布式事務處理和集中管理等,因而會對你特殊的用途有很大的幫助。是否選用,還在于你對擴展應用是否有需求以及對多DBMS的支持。

            談到這兒,我對模式3和模式4作一個總結:兩者都是純Java實現的驅動,因而不需要數據庫廠商提供附加的軟件,就可以運行在任何標準的Java平臺,性能上比較高效、可靠。

            了解上述3種JDBC的實現模式之后,模式2就更容易闡釋了,你可以理解它為前三者利弊平衡的妥協產物:

            1. 借鑒模式1利用客戶機本地代碼庫,加速數據訪問的執行,但卻摒除ODBC標準,而是支持廠商自己指定的性能擴展
            2. 借鑒模式3利用多層結構,上層用Java實現,利于跨平臺應用和支持多數據庫,但下層卻改為本地代碼,加速執行速度
            3. 借鑒模式4和數據庫結合緊密的優點,部分用Java實現,更是對數據庫性能有很大的擴展

            這種開放和高性能的特征得到了業界的肯定,因而被主要的數據庫廠商強烈推薦。盡管它需要你下載本地代碼庫到客戶機,但相對于你訪問數據庫速度的提高,這些應該只是舉手之勞了。下面對4種實現JDBC的模式選擇,歸納一下選擇的順序(當然是指你有選擇余地的時候,不存在的話向后推延):

          編號 選擇過程分析 選擇順序
          1 實驗性環境下,盡可能選擇易于配置的驅動,利于Java程序的開發,后期可在對應用環境進行判斷后,再對JDBC模式進行選擇 1>2>3>4
          2 小型企業級環境下,不需要對多數據庫的支持,因而模式2和3的有些優點并不能體現出來,強烈推薦你選擇模式4的JDBC驅動 4>2=3>1
          3 大型企業級環境下,需要對多數據庫的支持,模式2和3各有千秋,但是更多情況下是你會選擇速度較快的模式2 2>3>4>1

            對于不同廠商提供的但應用相同模式的JDBC接口,理論上比較不出效率的高低,你只有通過一定的工具,例如Benchmark等,對它們進行比較才能更有利于你的選擇。因為暫時不存在第三方提供的數據比較結果,所以這些問題需要你對上述內容有了透徹理解之后自行解決。

            Java程序中SQL語句格式的優化

            這個時候,你也許還在為找不到合適的JDBC驅動而一籌莫展,也許為自己在凌晨3點下載的JDBC驅動通過了測試而欣喜若狂,但是并不說明你對程序的優化工作已經無關緊要了。切記,對整個軟件系統的優化,包括每個環節的優化,要不有可能你會前功盡棄。我在這兒不和大家討論Java程序的算法,而是簡單闡述一下選擇SQL語句格式的必要和如何選擇對自己有利的SQL語句格式。看下面兩段程序片斷:

            Code Fragment 1:

            String updateString = "UPDATE COFFEES SET SALES = 75 " + "WHERE COF_NAME LIKE 'Colombian'";
            stmt.executeUpdate(updateString);

            Code Fragment 2:

            PreparedStatement updateSales = con.prepareStatement("UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? ");
            updateSales.setInt(1, 75);
            updateSales.setString(2, "Colombian");
            updateSales.executeUpdate();

            片斷2和片斷1的區別在于,后者使用了PreparedStatement對象,而前者是普通的Statement對象。PreparedStatement對象不僅包含了SQL語句,而且大多數情況下這個語句已經被預編譯過,因而當其執行時,只需DBMS運行SQL語句,而不必先編譯。當你需要執行Statement對象多次的時候,用PreparedStatement對象將會大大降低運行時間,當然也加快了訪問數據庫的速度。

            這種轉換也給你帶來很大的便利,不必重復SQL語句的句法,而只需更改其中變量的值,便可重新執行SQL語句。選擇PreparedStatement對象與否,在于相同句法的SQL語句是否執行了多次,而且兩次之間的差別僅僅是變量的不同。如果僅僅執行了一次的話,它應該和普通的Statement對象毫無差異,體現不出它預編譯的優越性。

            軟件模型中對數據庫訪問的設計模式的優化

            在我閱讀J2EE藍圖和JDO草案的過程中,我發現了訪問模式對數據庫訪問的影響,因而想在本文中闡述如何針對自己的軟件需求選擇合適的軟件模式。

            J2EE藍圖的設計者在Java Pet Store示例應用中使用了MVC(Model-View-Controller)體系,給許多J2EE設計模式提供了背景。我要談及的三種設計模式是:Data Access Object、Fast Lane Reader、Page-by-Page Iterator,它們為加快數據存取速度提供了一些可以在系統設計階段值得我們借鑒的想法。

            Data Access Object

            將商業邏輯從數據存取邏輯中分離出來,把存取的資源改編,從而使資源可以容易和獨立地轉變。

            依賴于底層數據資源的特殊要素(例如數據庫的供應商)的商業組件,常將商業邏輯和數據存取邏輯配合起來,只能使用特殊類型的資源,而使用不同類型的資源時,復用將會非常困難,因此,只能服務于有限的市場領域。DAO(Data Access Object)即是將數據存取邏輯從EJB中抽去出來抽象為一個獨立的接口,EJB根據接口的操作執行商業邏輯,而接口針對使用的數據資源實現為DAO對象。

            在Java Pet Shop這個例子中,OrderEJB組件通過關聯的OrderDAO類訪問數據庫,自身則關注于商業邏輯的實現。在調度階段,將配置某一類(OrderDAOCS、OrderDAOOracle或OrderDAOSybase)為OrderDAO的實現,而OrderEJB無須任何更改。圖3更能幫助你明白其中的道理:


          圖3 Data Access Object的設計模式

            此舉增加了數據存取的彈性、資源的獨立性和擴展性,但復雜度有相應的提高,其它附帶的問題我們不在這兒討論。

            Fast Lane Reader

            拋棄EJB,加速只讀數據的存取。

            有些時候,高效地存取數據比獲得最新的數據更重要。在Java Pet Store中,當一個用戶瀏覽商店的目錄時,屏幕與數據庫內容吻合不是至關緊要的,相反,迅速顯示和重新獲得非常重要。FLR模式可以加速從資源中重新獲得大型的列數據項的速度,它不用EJB,而是更直接地通過DAO來存取數據,從而消除EJB的經常開支(例如遠程方法調用、事務管理和數據序列化等)。

            在Java Pet Store這個例子中,當一個用戶瀏覽目錄時,通過CatalogDAO(而不是CatalogEJB)從數據庫加載數據項,而CatalogDAO是一個Fast Lane Reader的實例,使得讀訪問變得迅速,如圖4:


          圖4 Fast Lane Reader設計模式

            與DAO模式不同的是,FLR是一個優化的模式,但不是要替代原有的訪問機制,而是作為補充使其完備。當你頻繁地只讀大型的列數據和不必存取最新的數據時,使用FLR將是非常合適的。

            Page-by-Page Iterator

            為了高效地存取大型的遠程數據列,一下子通過重新獲得其元素為一個子列的Value Object(提高遠程傳輸效率的設計模式,這兒不詳盡描述)。

            分布式數據庫的應用經常需要用戶考慮一長列數據項,例如一個目錄或一個搜索結果的集合。在這些情況下,立刻提供全列的數據經常不必要(用戶并不是對所有的數據項感興趣)或不可能(沒有足夠的空間)。此外,當重新獲得一列數據項時,使用Entity Bean的代價將非常高昂,一個開銷來自于使用遠程探測器來收集Requested Bean,另外,更大的開銷來自對每個Bean產生遠程調用以從用戶獲得數據。

            通過Iterator,客戶機對象能一下子重新獲得一個子列或者頁的Value Object,每一頁都剛好滿足客戶機的需求,因此,程序使用較少的資源滿足了客戶機的立刻需求。

            在Java Pet Store這個例子中,JSP頁面product.jsp任何時候只顯示一個數據列的一部分,從ProductItemListTag(Page-by-Page Iterator)重新獲得數據項,當客戶機希望看到列中的別的數據項,product.jsp再次調用Iterator重新獲得這些數據項,流程見圖5:


          圖5 Page-by-Page Iterator設計模式

            以上設計模式的應用向我們表明,在某些特殊情況下,優化對數據庫的訪問模型,既可滿足用戶的需求又可提高訪問數據庫的效率。這給我們一個思路,就是:在你的硬件環境可能會產生瓶頸的情況下,可以通過對軟件模型的優化來達到滿足需求的目的。上述三種設計模式的應用情形為:

          Data Access Object 需要將商業邏輯和數據存取邏輯分離;
          在調度的時刻,需要支持選擇數據源的類型;
          使用的數據源的類型的變化,對商業對象或其它客戶端完成數據存取沒有影響。
          Fast Lane Reader 面對大型的列數據,需要經常的只讀訪問;
          訪問最新的數據并不是至關緊要的事情。
          Page-by-Page Iterator 存取大型的服務器端數據列;
          任何時刻,用戶只對列的一部分內容感興趣;
          整個列的數據不適合在客戶端顯示;
          整個列的數據不適合在存儲器中保存;
          傳輸整個列的數據將耗費太多的時間。

            在顯示商品目錄的時候,我們選擇了DAO和FLR的結合,因為它們兩者的條件都得到了滿足(需要分離商業邏輯和數據存取邏輯,經常的只讀訪問和對即時性不敏感),此時應用將會大大發揮它們的優點。而在進行內容檢索的時候,我們會選擇PPI,因為也許檢索出了上千條的記錄,但是用戶沒有興趣立即閱讀全部內容,而是一次十條地閱讀,或者他在閱讀完前十條記錄后發覺自己的目的已經達到,接下來瀏覽別的網頁了,都不必我們一次性地傳輸上千條記錄給他,所以也是PPI的應用條件得到了滿足,結果則是此模式的優點得到了發揮,又不影響全局的數據訪問。

            在進行軟件模型的設計時,整體的框架可以應用某些優秀的、通用的設計模式,這樣既加快模型的建立速度,又能和其它系統集成。但是,碰到一些瓶頸問題的情況下,我們就需要對局部的設計模式做一些調整,以優化整個系統,上述三個模式就是對原有體系的補充,它們并沒有對整體的框架做出巨大的改變,卻突破了某些瓶頸(瓶頸往往是局部的)障礙,讓我們的產品更好地服務于用戶。

            將深入研究的問題

            開篇至今,我們主要探討了軟件層次上的解決問題,但是,必須肯定一點,如果你的硬件環境非常差(運行Java都有困難)或非常好(額外的存儲空間、超快的運算速度和富裕的網絡帶寬),上述途徑對你來說很難有大的幫助。前一種情況,我建議你升級硬件設備到軟件廠商推薦的配置(強烈反對最小配置),以使應用服務器、數據庫、Java等軟件能夠運行自如;后一種情況,我沒什么話可說,花錢是解決這個問題最好的辦法。

            本文并未談及線程池和告訴緩沖這兩個非常重要的概念,因為筆者認為,它們是針對局部時間高訪問量的瓶頸問題的解決,不能理解為簡單的速度瓶頸問題,所以我會在下一篇文章中分析這種特殊的情況和提出解決問題的辦法。也許你對這一點更關心一些,認為自己的問題就出在這個地方,這是非常好的思考問題的方式,你已經抓住了問題的關鍵。但是,我還是建議你通讀一下本文,讓自己對速度瓶頸問題有更好的理解,并掌握在解決問題的過程中,分辨常態和暫態,從而選擇不同的思路入手。其實,本文談及的就是速度瓶頸問題的常態,而下一篇文章討論的將會是暫態,希望你能夠漸入佳境。

            JDO(Java Data Object)是需要我們關注的一個API,它定義了新的數據存取模型,直接借鑒了DAO設計模式。不同的數據源,有不同的數據存取技術,就有不同的API供開發人員使用。JDO正是為了解決這個問題而產生的,它實現了即插即用的數據存取的實現和持久信息(包括企業數據和本地存儲的數據)以Java為中心的視圖。因此,開發人員只關注創建那些實現商業邏輯的類和用它們來表現數據源的數據,而這些類和數據源之間的映射則由那些EIS領域的專家來完成。如果大家對JDO感興趣的話,那么我會寫第三篇文章把其詳細介紹給大家,并給出示例應用。

          posted @ 2006-08-22 09:32 Lansing 閱讀(445) | 評論 (0)編輯 收藏
          批量處理JDBC語句提高處理速度

          作者:佚名????來自:未知

            有時候JDBC運行得不夠快,這使得有些程序員使用數據庫相關的存儲過程。作為一個替代方案,可以試試使用Statement 的批量處理特性看看能否同時執行所有的SQL以提高速度。

            存儲過程的最簡單的形式就是包含一系列SQL語句的過程,將這些語句放在一起便于在同一個地方管理也可以提高速度。Statement 類可以包含一系列SQL語句,因此允許在同一個數據庫事務執行所有的那些語句而不是執行對數據庫的一系列調用。

            使用批量處理功能涉及下面的兩個方法:
            · addBatch(String) 方法
            · executeBatch方法

            如果你正在使用Statement 那么addBatch 方法可以接受一個通常的SQL語句,或者如果你在使用PreparedStatement ,那么也可以什么都不向它增加。executeBatch 方法執行那些SQL語句并返回一個int值的數組,這個數組包含每個語句影響的數據的行數。如果將一個SELECT語句或者其他返回一個ResultSet的SQL語句放入批量處理中就會導致一個SQLException異常。

            關于java.sql.Statement 的簡單范例可以是:

            Statement stmt = conn.createStatement();
            stmt.insert("DELETE FROM Users");
            stmt.insert("INSERT INTO Users VALUES("rod", 37, "circle")");
            stmt.insert("INSERT INTO Users VALUES("jane", 33, "triangle")");
            stmt.insert("INSERT INTO Users VALUES("freddy", 29, "square")");
            int[] counts = stmt.executeBatch();

            PreparedStatement 有些不同,它只能處理一部分SQL語法,但是可以有很多參數,因此重寫上面的范例的一部分就可以得到下面的結果:

            // 注意這里沒有DELETE語句
            PreparedStatement stmt = conn.prepareStatement("INSERT INTO Users VALUES(?,?,?)");

            User[ ] users = ...;
            for(int i=0; i<users.length; i++) {
             stmt.setInt(1, users[i].getName());
             stmt.setInt(2, users[i].getAge());
             stmt.setInt(3, users[i].getShape());
             stmt.addBatch( );
            }
            int[ ] counts = stmt.executeBatch();

            如果你不知道你的語句要運行多少次,那么這是一個很好的處理SQL代碼的方法。在不使用批量處理的情況下,如果添加50個用戶,那么性能就有影響,如果某個人寫了一個腳本添加一萬個用戶,程序可能變得很糟糕。添加批處理功能就可以幫助提高性能,而且在后面的那種情況下代碼的可讀性也更好。

          posted @ 2006-08-22 09:24 Lansing 閱讀(433) | 評論 (0)編輯 收藏
               摘要: Avalon的簡要歷史以及創建它所有的設計原則概述 事情是從Apache JServ項目開始的。Stefano Mazzocchi和其它協助開發Apache JServ的人員認識到項目中所用到的一些模式很通用,足以用于創建一個服務器框架。 在1999年1月27日,星期三(在JServ ...  閱讀全文
          posted @ 2006-08-18 20:14 Lansing 閱讀(2398) | 評論 (0)編輯 收藏
          僅列出標題
          共4頁: 上一頁 1 2 3 4 下一頁 
          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          歡迎探討,努力學習Java哈

          常用鏈接

          留言簿(3)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          Lansing's Download

          Lansing's Link

          我的博客

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 固镇县| 蒙山县| 临城县| 黔西县| 武山县| 叙永县| 长治县| 九寨沟县| 壤塘县| 合肥市| 江川县| 敦煌市| 泽州县| 寿宁县| 澎湖县| 静安区| 漳州市| 湖北省| 遵义市| 澄迈县| 鄂州市| 定远县| 嘉祥县| 敖汉旗| 永靖县| 华坪县| 内黄县| 普陀区| 城固县| 漯河市| 大同县| 汾西县| 虹口区| 茶陵县| 山西省| 柯坪县| 寿阳县| 竹溪县| 宜君县| 瓮安县| 嘉义县|