自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

在Google Java App Engine上實(shí)現(xiàn)文檔存儲(chǔ)和搜索

原創(chuàng)
開發(fā) 開發(fā)工具 后端
Google App Engine的Java支持已于今年4月發(fā)布,對(duì)于Java開發(fā)者而言這是極大的好處:App Engine具有伸縮性強(qiáng),管理界面強(qiáng)大等特點(diǎn),而且對(duì)于小型應(yīng)用來(lái)說(shuō)是完全免費(fèi)的。本文演示了如何在App Engine上編寫實(shí)現(xiàn)文檔的存儲(chǔ)和搜索功能。

【51CTO技術(shù)譯文】為什么Java程序員要考慮使用Google的Java App Engine呢,主要有以下幾點(diǎn)原因:只要你的頁(yè)面訪問(wèn)量每月不超過(guò)500萬(wàn),Google就免費(fèi)向你提供空間。如果訪問(wèn)量超過(guò)了這一限額,你也可以隨時(shí)通過(guò)升級(jí)為付費(fèi)用戶取消這一限制。

◆Google的App Engine 平臺(tái)(包括Java和Python版本)讓你不用做什么額外工作就有很強(qiáng)的伸縮性

◆App Engine 提供了一個(gè)功能很強(qiáng)的管理界面,你可以通過(guò)它查看錯(cuò)誤日志,瀏覽你所保存的數(shù)據(jù),分析程序的性能(例如請(qǐng)求響應(yīng)時(shí)間等),還可以實(shí)時(shí)監(jiān)控你所部署的應(yīng)用。即便是和Amazon的EC2這樣優(yōu)秀的Web控制臺(tái)比起來(lái),Google的Web應(yīng)用程序管理功能也毫不遜色。

◆只要你愿意,你也可以通過(guò)App Engine SDK 把App Engine 上的應(yīng)用遷移到你自己的服務(wù)器上,當(dāng)然,這樣就會(huì)損失一些伸縮性(scalability)了。

◆因?yàn)樵贏pp Engine上開發(fā)程序時(shí)使用的都是標(biāo)準(zhǔn)的 API,所以當(dāng)你要把應(yīng)用移植部署到其它平臺(tái)上時(shí),就只需要對(duì)程序作非常小的改動(dòng)了。不過(guò)反過(guò)來(lái)做就不是這么簡(jiǎn)單了。比如說(shuō)如果你的程序調(diào)用大量的J2EE API函數(shù),或者說(shuō)依賴于關(guān)系型數(shù)據(jù)庫(kù)等等,那么把這些程序移植到App Engine上就非常麻煩。

◆那些用J2EE寫Web程序的開發(fā)者們可能一開始會(huì)覺(jué)得App Engine 的種種限制讓人覺(jué)得很不適應(yīng),但是這樣做的好處也是很明顯的,服務(wù)器的花費(fèi)將大大減少。如果你想要更大的自由度和伸縮性,那么你還可以考慮Amazon的EC2服務(wù)(我是既用App Engine,也用EC2)。

本文接下來(lái)將介紹Java開發(fā)者如何使用Google應(yīng)用程序引擎。它演示了如何在App Engine上編寫實(shí)現(xiàn)文檔的存儲(chǔ)和搜索功能。本文還探討了Java App Engine文檔里的一些有用技術(shù)和應(yīng)用程序示例。

你需要作的準(zhǔn)備 

◆Eclipse或IntelliJ IDEA開發(fā)環(huán)境 

◆一個(gè)App Engine 帳號(hào),如果還沒(méi)有的話,在這里申請(qǐng)(沒(méi)有App Engine 帳號(hào)的開發(fā)者可以通過(guò)在你自己電腦上安裝App Engine SDK體驗(yàn)它) 

◆下載App Engine SDK 供本地開發(fā)時(shí)使用 

◆安裝Eclipse的或IntelliJ 的Java App Engine 插件。  
 
示例工程里的文件

示例工程里的文件 

圖1 示例工程里的文件

許多Java開發(fā)人員使用 Lucene (或基于Lucene的框架)來(lái)實(shí)現(xiàn)搜索功能。但是,在App Engine環(huán)境下使用Lucene的內(nèi)存索引模式?jīng)]有什么好處。我們的這個(gè)示例工程另辟蹊徑在App Engine平臺(tái)上實(shí)現(xiàn)了搜索功能。

App Engine的持久性數(shù)據(jù)存儲(chǔ)效率是非常高的,但它不使用關(guān)系模型,也沒(méi)有Hibernate這樣的對(duì)象關(guān)系映射(Object Relational Mapping ,ORM)框架。不過(guò),App Engine還是提供了對(duì)一些標(biāo)準(zhǔn)的持久性API,如JDO,JPA,以及JCache。我們的示例程序使用JDO實(shí)現(xiàn)數(shù)據(jù)持久(data persistence)。

這個(gè)程序部署在這里。每個(gè)使用這個(gè)演示程序的人都可以把數(shù)據(jù)清空從頭再來(lái),所以你這次添加的信息下次可以就會(huì)看不到了。

作者注:這個(gè)程序演示了JDO的使用以及如何用JDO實(shí)現(xiàn)搜索,為了突出重點(diǎn),程序沒(méi)有增加對(duì)多用戶這些功能的支持。

圖1顯示了這個(gè)Java App Engine項(xiàng)目所包含的文件。后續(xù)的章節(jié)將詳細(xì)介紹packagecom.kbsportal.model 里的模型類和 com.kbsportal.persistence 里的持久類PMF。由于packagecom.kbsportal.util這個(gè)包里的各種類和App Engine里的差別較大,我們就不在這里作過(guò)多討論了。如果要詳細(xì)了解這些,你可以看看我們的源代碼以及JSP文件(在 war/WEB-INF目錄里)。我們也會(huì)對(duì)JSP文件里某些Java代碼片段加以解釋。

使用JDO實(shí)現(xiàn)數(shù)據(jù)持久化

JDO是一個(gè)用于持久化Java對(duì)象的古老API。起初,為了實(shí)現(xiàn)持久化存儲(chǔ),JDO要求開發(fā)者必須編寫和維護(hù)XML文件,以提供Java類的數(shù)據(jù)映射屬性。Google使用 DataNucleus 工具自動(dòng)完成這一過(guò)程。你只需要在你的Java模型類里面加以注解,DataNucleus工具就會(huì)自動(dòng)為你維護(hù)正確的數(shù)據(jù)映射關(guān)系。如果使用了Eclipse的或IntelliJ IDEA的App Engine插件,當(dāng)你編寫持久類時(shí),DataNucleus工具就會(huì)自動(dòng)在后臺(tái)作用。

警告:JDO和App Engine放到一起有時(shí)候會(huì)產(chǎn)生兼容性問(wèn)題。如果你是在本地用Eclipse開發(fā),只要?jiǎng)h除目錄 WEBAPP /war/WEB-INF/ appengine-generated/ local_db.bin里的文件。 如果你的Web應(yīng)用已經(jīng)部署上去了而且要修改模型類,那么你只需在App Engine控制臺(tái)中把已有的索引文件刪除即可

以下各節(jié)將介紹兩個(gè)持久類的實(shí)現(xiàn)并探討這些基于JDO實(shí)現(xiàn)的代碼。

#p#

文檔模型類

Eclipse或IntelliJ IDEA的App Engine插件與JDO以及DataNucleus工具的組合非常好用。使用這個(gè)組合設(shè)計(jì)和實(shí)現(xiàn)你自己的模型文件,并添加必須的注解,這些對(duì)你來(lái)說(shuō)應(yīng)該不成問(wèn)題。不過(guò)你還是要注意DataNucleus工具在后臺(tái)運(yùn)行時(shí)所提示的錯(cuò)誤信息。

在開始設(shè)計(jì)實(shí)現(xiàn)自己的持久類前,不妨先看看下面這個(gè)模型類,它是用來(lái)反映一個(gè)文件模型的。這個(gè)類在定義時(shí)會(huì)引入所需的JDO 類(實(shí)際上你的編輯器會(huì)自動(dòng)幫你填寫這些包含語(yǔ)句)。第一行注釋聲明了這個(gè)類是持久的。這個(gè)類被標(biāo)識(shí)為APPLICATION,這樣你就可以為那些創(chuàng)建后就將持久存在的對(duì)象分配ID。如果你要為數(shù)據(jù)存儲(chǔ)對(duì)象分配ID,那么你可以把類型指定為DATASTORE。

  1. package com.kbsportal.model;  
  2.  
  3. import javax.jdo.annotations.IdentityType;  
  4. import javax.jdo.annotations.PersistenceCapable;  
  5. import javax.jdo.annotations.Persistent;  
  6. import javax.jdo.annotations.PrimaryKey;  
  7.  
  8. @PersistenceCapable(identityType=IdentityType.APPLICATION)  
  9. public class Document {  
  10.  

這段代碼聲明了把成員變量uri作為在數(shù)據(jù)存儲(chǔ)里查找Document對(duì)象時(shí)的主鍵。JDO的索引主鍵也被設(shè)為URI。本文的示例文本存儲(chǔ)在IndexToken這個(gè)類里面使用了這個(gè)主鍵(IndexToken類將在下一節(jié)進(jìn)一步討論)。這段代碼還特別說(shuō)明了title, content以及numWords這幾個(gè)成員變量要持久保存。

  1. @PrimaryKey private String uri;  
  2. @Persistent private String title;  
  3. @Persistent private String content;  
  4. @Persistent private int numWords; 

類聲明里的其它部分則不包含JDO具體說(shuō)明。

  1. public Document(String uri, String title, String content) {  
  2.     super();  
  3.     setContent(content);  
  4.     this.title = title;  
  5.     this.key = uri;  
  6.   }  
  7.   public String getUri() { return key; }  
  8.   public String getTitle() { return title; }  
  9.   public void setTitle(String title) { this.title = title; }  
  10.   public String getContent() { return content; }  
  11.   public void setContent(String content) {  
  12.     this.content = content;  
  13.     this.numWords = content.split("[\\ \\.\\,\\:\\;!]").length;  
  14.     System.out.println("** numWords = " + numWords + " content: "+content);  
  15.   }  
  16.   public int getNumWords() { return numWords; }  
  17. }  

注意在內(nèi)容字符串上所作的長(zhǎng)度限制;GoogleApp Engine的數(shù)據(jù)存儲(chǔ)限制字符串不得超過(guò)500個(gè)字符。(使用com.google.appengine.api.datastore.Textfors可以獲得沒(méi)有長(zhǎng)度限制的字串。 )

#p#

IndexToken模型類

該IndexToken類基于JDO實(shí)現(xiàn)了搜索功能。這個(gè)類有兩種工作模式:整詞索引、整詞及詞前綴索引。在源文件的頭部你可以通過(guò)一個(gè)常量指定它的工作模式:

  1. package com.kbsportal.model;  
  2.  
  3. import java.util.ArrayList;  
  4. import java.util.Collections;  
  5. import java.util.Comparator;  
  6. import java.util.HashMap;  
  7. import java.util.List;  
  8.  
  9. import javax.jdo.PersistenceManager;  
  10. import javax.jdo.annotations.IdGeneratorStrategy;  
  11. import javax.jdo.annotations.IdentityType;  
  12. import javax.jdo.annotations.Index;  
  13. import javax.jdo.annotations.PersistenceCapable;  
  14. import javax.jdo.annotations.Persistent;  
  15. import javax.jdo.annotations.PrimaryKey;  
  16.  
  17. import com.kbsportal.persistence.PMF;  
  18. import com.kbsportal.util.NoiseWords;  
  19. import com.kbsportal.util.Pair;  
  20. import com.kbsportal.util.SearchResult;  
  21.  
  22. @PersistenceCapable(identityType=IdentityType.APPLICATION)  
  23. public class IndexToken {  
  24.   static boolean MATCH_PARTIAL_WORDS = true;  // package visibility  

把這個(gè)標(biāo)志設(shè)置為true,就會(huì)開啟單詞的前綴匹配功能,類似于搜索關(guān)鍵字自動(dòng)校正功能。

現(xiàn)在我們?cè)摽纯慈绾谓⑺饕危赡苓€包括單詞前綴的索引片段)以及如何確定每個(gè)索引片段的匹配度。以下是具體的代碼(來(lái)自IndexToken.java包里的源文件,它是作為一個(gè)單獨(dú)的局部類實(shí)現(xiàn)的,以方便在其他項(xiàng)目重復(fù)使用) :

  1. class StringPrefix {  
  2.   public List getPrefixes(String str) {  
  3.     List ret = new ArrayList();  
  4.     String[] toks = str.toLowerCase().split("[\\ \\.\\,\\:\\;\\(\\)\\-\\[\\]!]");  
  5.     for (String s : toks) {  
  6.       if (!(NoiseWords.checkFor(s))) {  
  7.         if (!IndexToken.MATCH_PARTIAL_WORDS) { // exact words only  
  8.           ret.add(new Pair(s, 1f));  
  9.         } else { // or, also match word prefixes  
  10.           int len = s.length();  
  11.           if (len > 2) {  
  12.             ret.add(new Pair(s, 1f));  
  13.             if (len > 3) {  
  14.               int start_index = 1 + (len / 2);  
  15.               for (int i = start_index; i < len; i++) {  
  16.                 ret.add(new Pair(s.substring(0, i), (0.25f * (float) i) / (float) len));  
  17.               }  
  18.             }  
  19.           }  
  20.         }  
  21.       }  
  22.     }  
  23.     return ret;  
  24.   }  
  25. }  

應(yīng)用中的一些理念

通過(guò)使用 Peter Norvig的拼寫檢查算法可以實(shí)現(xiàn)更完整的拼寫檢查功能。使用相對(duì)較低的相關(guān)系數(shù)可以生成錯(cuò)誤的拼寫序列和IndexToken實(shí)例。在我所寫的書"Practical Artificial Intelligence Programming in Java"的第9章里有一個(gè)Java版本的 Norvig算法實(shí)現(xiàn)。

#p#

其它實(shí)現(xiàn)方法

我在另一個(gè)大項(xiàng)目里使用了這些代碼,那個(gè)項(xiàng)目需要一個(gè)彈出式的文字補(bǔ)全提示;我們存儲(chǔ)的這些前綴起到了“雙重作用”。本文主要講解基于JDO的文件存儲(chǔ)和搜索,但你可以簡(jiǎn)單地使用一個(gè)JavaScript庫(kù),例如 Prototype或GWT實(shí)現(xiàn)彈出的提示菜單。另外,你也可以只把詞干作為 IndexToken實(shí)例保存。點(diǎn)擊此處查看相關(guān)Java詞根提取程序。
 
Pair這個(gè)類是在com.kbsportal.util包里實(shí)現(xiàn)的,這個(gè)包里面還有另外兩個(gè)類: NoiseWords和SearchResults 。我們?cè)诖瞬辉僮肪窟@些類的細(xì)節(jié)。今后我們將深入這些源文件。

要完成IndexToken,以及示例程序的其余部分,我們要用到JDO的API,首先是在類屬性說(shuō)明里加入這些注解:

  1. @PrimaryKey 
  2. @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)  
  3. private Long id;  
  4. @Persistent @Index private String textToken;  
  5. @Persistent private String documentUri;  
  6. @Persistent private Float ranking;  

@Persistent 標(biāo)示這個(gè)成員在整個(gè)對(duì)象被保存時(shí)要被插入到數(shù)據(jù)存儲(chǔ)里去。valueStrategy的值是可選的,按上面這樣設(shè)置是表明你希望數(shù)據(jù)存儲(chǔ)為你這個(gè)類的ID屬性自動(dòng)賦值。@PrimaryKey 注釋讓DataNucleus工具知道,在查找數(shù)據(jù)存儲(chǔ)區(qū)里的這種對(duì)象時(shí)要以該參數(shù)為主鍵。

作者注:通常情況下都是通過(guò)主鍵獲取對(duì)象。然而,在我們這個(gè)程序里,我們將要通過(guò)IndexToken類的參數(shù)值 textToken 來(lái)查找對(duì)象。但是我們不能使用參數(shù)textToken 作為主鍵,因?yàn)檫@樣有可能導(dǎo)致在數(shù)據(jù)存儲(chǔ)區(qū)里有主鍵一樣的不同實(shí)例出現(xiàn)。

下面這個(gè)成員方法能獲取文件ID(文件的URI)以及文件中的一段文字,實(shí)例化一個(gè)IndexToken類:

  1. public static void indexString(String document_id, String text) {  
  2.     PersistenceManager pm = PMF.get().getPersistenceManager();  
  3.     List lp = new StringPrefix().getPrefixes(text);  
  4.     for (Pair p : lp) {  
  5.         if (p.str.length() > 0 && !Character.isDigit(p.str.charAt(0))) {  
  6.           pm.makePersistent(new IndexToken(document_id, p.str, p.f));  
  7.         }  
  8.     }     
  9.   }  

這段代碼用到了StringPrefix 類。另外還使用了工具類PMF(等下我們就會(huì)更詳細(xì)地去了解它)來(lái)獲得一個(gè)App Engine持久管理器(persistence manager)的實(shí)例。這類似于一個(gè)JDBC 連接對(duì)象。

在IndexToken里還有一個(gè)值得一提的地方就是search這個(gè)靜態(tài)方法.

  1. public static List search(String query) {  
  2.     List< SearchResult> ret = new ArrayList< SearchResult>();  
  3.     PersistenceManager pm = PMF.get().getPersistenceManager();  
  4.     String [] tokens = query.toLowerCase().split(" ");  
  5.     HashMap matches = new HashMap();  

此方法返回SearchResult類的實(shí)例。查詢字符串被轉(zhuǎn)換為小寫并被分割。對(duì)于每一個(gè)片段,你都將再次用StringPrefix計(jì)算前綴(以及原始單詞) ,計(jì)算結(jié)果將用于查找包含這些關(guān)鍵詞的文件:

  1. for (String token : tokens) {  
  2.       List lp = new StringPrefix().getPrefixes(token);  
  3.       for (Pair p : lp) {  
  4.         String q2 = "select from " + IndexToken.class.getName() + "  where textToken == '" + p.str + "'";  
  5.         @SuppressWarnings("unchecked")  
  6.         List itoks = (List) pm.newQuery(q2).execute();  

這個(gè)查詢字符串可能看起來(lái)會(huì)覺(jué)得有點(diǎn)像標(biāo)準(zhǔn)的SQL語(yǔ)句 ,但不是。其實(shí)它們是JDO的查詢語(yǔ)言( JDOQL ) 。它從一個(gè)在數(shù)據(jù)存儲(chǔ)區(qū)持久化了的類里面取數(shù)據(jù),而不是像SQL語(yǔ)句那樣通過(guò)一個(gè)數(shù)據(jù)庫(kù)的表名來(lái)提取數(shù)據(jù)。TextToken就是IndexToken 的一個(gè)持久化參數(shù)。這個(gè)JDOQL能返回?cái)?shù)據(jù)存儲(chǔ)區(qū)中所有textToken成員參數(shù)與查詢關(guān)鍵字匹配的IndexToken實(shí)例。(51CTO編者注:JDOQL是JDO的查詢語(yǔ)言;它有點(diǎn)象SQL,但卻是依照J(rèn)ava的語(yǔ)法的。)

搜索功能的其它部分實(shí)現(xiàn)起來(lái)就沒(méi)有什么難點(diǎn)了。只需要保存所有的文件匹配以及根據(jù)匹配度計(jì)算出的排名權(quán)重。

  1. for (IndexToken it : itoks) {  
  2.           Float f = matches.get(it.getDocumentUri());  
  3.           if (f == null) f = 0f;  
  4.           f += it.getRanking();  
  5.           matches.put(it.getDocumentUri(), f);  
  6.         }  
  7.       }     
  8.     }  

這樣我們就建立好了查詢關(guān)鍵字與文件之間的映射關(guān)系,還知道了這些文件的URI以及排名權(quán)重。我們只需要把匹配結(jié)果從數(shù)據(jù)存儲(chǔ)區(qū)里取出來(lái)就可以了(只有這樣我們才有結(jié)果可顯示), 然后把這些與關(guān)鍵字相匹配的文檔按匹配度從高到低排列,就形成了搜索結(jié)果。

  1. for (String s : matches.keySet()) {  
  2.       String q2 = "select from " + Document.class.getName() + "  where uri == '" + s + "'";  
  3.       @SuppressWarnings("unchecked")  
  4.       List itoks = (List) pm.newQuery(q2).execute();  
  5.       if (!itoks.isEmpty()) {  
  6.         int num_words = itoks.get(0).getNumWords();  
  7.         ret.add(new SearchResult(s, matches.get(s) / (float)(num_words), itoks.get(0).getTitle()));  
  8.       }  
  9.     }  
  10.     Collections.sort(ret, new ValueComparator());  
  11.     return ret;  
  12.   }  

ValueComparato這個(gè)類是在源文件IndexToken.java里定義的,作用就是對(duì)搜索結(jié)果進(jìn)行排序。

  1. static class ValueComparator implements Comparator {  
  2.     public int compare(SearchResult o1, SearchResult o2) {  
  3.       return (int)((o2.score - o1.score) * 100);  
  4.     }  
  5.   }  

處理持久性數(shù)據(jù)存儲(chǔ):PMF類

我們這里所展示的PMF類代碼是從Google的文檔里復(fù)制過(guò)來(lái)的。這個(gè)類創(chuàng)建了一個(gè)私有的PersistenceManagerFactory實(shí)例并重用它。

  1. package com.kbsportal.persistence;  
  2. import javax.jdo.JDOHelper;  
  3. import javax.jdo.PersistenceManagerFactory;  
  4.  
  5. public final class PMF {  
  6.     private static final PersistenceManagerFactory pmfInstance =  
  7.         JDOHelper.getPersistenceManagerFactory("transactions-optional");  
  8.     private PMF() {}  
  9.     public static PersistenceManagerFactory get() {  
  10.         return pmfInstance;  
  11.     }  
  12. }  

#p#

示例程序的JSP頁(yè)面

在寫JSP頁(yè)面時(shí),我通常最開始是把Java代碼嵌入到JSP頁(yè)面里,到最后,我再把一些公用代碼提取出來(lái)放到自定義的JSP標(biāo)簽庫(kù)里,再給模型類添加上額外的行為。在這個(gè)程序里,我就不演示最后這幾步清理工作了。

作為首頁(yè)顯示的index.jsp頁(yè)面是用來(lái)顯示系統(tǒng)里所有的文件的。它也包含了一些可選的調(diào)試代碼(我通常會(huì)把這些調(diào)試代碼注釋掉),可以列出所有IndexToken類的實(shí)例(見 圖2 ) 。index.jsp 這個(gè)文件最開頭的部分引入了一些必要的類,定義了HTML頭信息,然后還引入了menu.jsp,這個(gè)文件是用來(lái)作分頁(yè)條的。

  1. < %@ page import="javax.jdo.*, java.util.*,   
  2.     com.kbsportal.model.*,com.kbsportal.persistence.PMF" %> 
  3. < %@ page language="java" contentType="text/html; charset=ISO-8859-1" 
  4.     pageEncoding="ISO-8859-1"%> 
  5. < !DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   
  6.    "http://www.w3.org/TR/html4/loose.dtd"> 
  7. < html> 
  8. < head> 
  9. < meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> 
  10. < title>KBSportal Java App Engine Search Demo< /title> 
  11. < /head> 
  12. < body> 
  13. < %@ include file="menu.jsp" %> 

列出所有文件 

圖2 列出所有文件:調(diào)試代碼列出了所有IndexToken 實(shí)例,并顯示了一些索引片段。

在IndexToken實(shí)例里我們已經(jīng)見過(guò)JDOQL查詢語(yǔ)句。在這里,查詢語(yǔ)句返回所有文件對(duì)象:

  1. < h2>All documents:< /h2> 
  2. < %  
  3.   PersistenceManager pm = PMF.get().getPersistenceManager();   
  4.   Query query = pm.newQuery(Document.class);  
  5.   try {  
  6.        List< Document> results = (List< Document>)   
  7.           query.execute();  
  8.        if (results.iterator().hasNext()) {  
  9.            for (Document d : results) {  
  10.              System.out.println("key: "+d.getUri() +   
  11.                 ", title: "+d.getTitle());  
  12. %> 
  13.                < h3>< %=d.getTitle()%>< /h3> 
  14.                < p>< %=d.getContent()%>< /p> 
  15. < %  
  16.            }  
  17.        }  
  18.   } finally {  
  19.       query.closeAll();  
  20.   }     
  21. %> 

這里我們沒(méi)有用JDOQL查詢語(yǔ)句,而是用了一個(gè)查詢對(duì)象來(lái)獲取數(shù)據(jù),這樣我們所獲得的查詢結(jié)果就在其它JSP文件里也可以使用了,如果你只想獲取某個(gè)特定標(biāo)題的文件,那么通過(guò)下面的代碼可以篩選結(jié)果:

  1. String title_to_find = "Dogs and Cats" 
  2. query.setFilter("title == " + title_to_find);  

index.jsp這個(gè)文件的后半部分也包含一些調(diào)試代碼,在調(diào)試Web程序時(shí)我們可能會(huì)需要啟用它。這段代碼與之前那段調(diào)試代碼幾乎完全一樣,只不過(guò)這段代碼顯示的是所有的IndexToken實(shí)例。

  1. query = pm.newQuery(IndexToken.class);  
  2.    try {  
  3.        List results = (List) query.execute();  
  4.        if (results.iterator().hasNext()) {  
  5.            for (IndexToken indexToken : results) { 

用于向數(shù)據(jù)存儲(chǔ)區(qū)添加文件的表單 

圖3  用于向數(shù)據(jù)存儲(chǔ)區(qū)添加文件的表單:這個(gè)JSP頁(yè)面提供了一個(gè)可以向系統(tǒng)增加“文件” 的HTML輸入框

new_document.jsp這個(gè)文件提供了一個(gè)可以向系統(tǒng)增加“文件” 的HTML輸入框。(見 圖3 ) 。下面的代碼是從new_document.jsp截取出來(lái)的,它的作用是頁(yè)面請(qǐng)求中是否包含表單數(shù)據(jù)。如果有的話,就向數(shù)據(jù)存儲(chǔ)區(qū)里插入一個(gè)Document實(shí)例。

  1. < %  
  2.   String url = request.getParameter("url");  
  3.   String title = request.getParameter("title");  
  4.   String text = request.getParameter("text");  
  5.   if (url!=null && title!=null && text!=null) {  
  6.    PersistenceManager pm =   
  7.       PMF.get().getPersistenceManager();  
  8.    try {  
  9.      Document doc = new Document(url, title, text);  
  10.      pm.makePersistent(doc);  
  11.      IndexToken.indexString(doc.getUri(), doc.getTitle() +   
  12.         " " + doc.getContent());  
  13.    } finally {  
  14.      pm.close();  
  15.    }  
  16.   }  
  17. %> 

makePersistent這個(gè)方法會(huì)被直接調(diào)用并把文件保存到數(shù)據(jù)存儲(chǔ)區(qū)。靜態(tài)方法IndexToken.indexString則把根據(jù)文件標(biāo)題和內(nèi)容生成的片段插入到數(shù)據(jù)存儲(chǔ)區(qū)里。

數(shù)據(jù)存儲(chǔ)區(qū) 

圖4 從數(shù)據(jù)存儲(chǔ)區(qū)里:刪除所有文件和索引片段 示例應(yīng)用程序需要一個(gè)簡(jiǎn)單的方法來(lái)清空數(shù)據(jù)存儲(chǔ)區(qū)里所有測(cè)試“文件”數(shù)據(jù)

由于此示例程序是公開托管在Google那里,它需要一個(gè)簡(jiǎn)單的方法來(lái)清除文件存儲(chǔ)區(qū)里所有的測(cè)試“文件”。delete_all.jsp這個(gè)jsp文件能從數(shù)據(jù)存儲(chǔ)里刪除所有的文件和索引片段(參見 圖4 ) 。

  1. PersistenceManager pm = PMF.get().getPersistenceManager();   
  2.   Query query = pm.newQuery(Document.class);  
  3.   try {  
  4.     List results = (List)   
  5.        query.execute();  
  6.     if (results.iterator().hasNext()) {  
  7.         for (Document d : results) {  
  8.             pm.deletePersistent(d);  
  9.         }  
  10.     }  
  11.   } finally {  
  12.     query.closeAll();  
  13.   }   
  14.  
  15.   query = pm.newQuery(IndexToken.class);  
  16.   try {  
  17.     List results = (List) query.execute();  
  18.     if (results.iterator().hasNext()) {  
  19.       for (IndexToken indexToken : results) {  
  20.           pm.deletePersistent(indexToken);  
  21.       }  
  22.     }  
  23.   } finally {  
  24.     query.closeAll();  
  25.   } 

search.jsp的JSP的文件包含了一個(gè)HTML搜索框(參見 圖5 ) 。以下是處理搜索操作的代碼:

  1. String query = "";  
  2.    String results = "< b>Results:< /b>< br/>";  
  3.    Object obj = request.getParameter("search");  
  4.    if (obj != null) {  
  5.      query = "" + obj;  
  6.      List hits = IndexToken.search(query);  
  7.      for (SearchResult hit : hits) {  
  8.        results += "< p>" + hit + "< /p>";  
  9.      }  
  10.    } 

搜索結(jié)果 

圖5 搜索結(jié)果: filesearch.jsp包含有一個(gè)HTML搜索框。

SearchResults類里新增的ToString 方法用于格式化搜索結(jié)果:

  1. public String toString() { return url +  
  2.    " - " + score + ": " + title; }  

成本低廉的解決方案

Google App Engine為我們提供了一套無(wú)成本(或低成本)的解決方案。盡管對(duì)于某些Web應(yīng)用服務(wù)來(lái)說(shuō),它可能并不是最佳的部署平臺(tái),但它絕對(duì)值得一試,而且絕對(duì)有資格成為我們開發(fā)工具箱里的備選項(xiàng)。

【App Engine相關(guān)文章推薦】

  1. 手把手教你在Google App Engine上運(yùn)行PHP
  2. Google App Engine免費(fèi)配額降低公告
  3. 開始您的第一個(gè)Google App Engine應(yīng)用
  4. Google App Engine:Java SDK 1.2.1發(fā)布
  5. Google App Engine對(duì)Java支持情況一覽
  6. Google App Engine:堅(jiān)定的站在Java的中心
責(zé)任編輯:yangsai 來(lái)源: 51CTO.com
相關(guān)推薦

2009-06-12 18:21:46

App Engine上

2009-09-10 10:11:44

Google App Java開發(fā)2.0

2009-09-07 10:42:01

Scala LiftGoogle App

2009-04-16 09:59:16

Google App PHPJava

2009-09-15 16:37:06

Google App 持久性

2009-04-08 16:47:11

GoogleApp EngineJava

2009-04-13 15:48:54

Google AppJavaSun

2009-04-09 08:54:07

App EnginegoogleJava

2009-09-04 09:41:34

Google App

2009-09-02 11:34:09

Google App

2009-04-09 09:53:43

GoogleAppEngineJava

2012-08-01 14:12:45

IBMdW

2009-05-14 09:47:30

GoogleApp EngineJava SDK

2009-08-11 11:23:41

什么是GAEGoogle App

2009-05-22 14:52:33

App Engine免費(fèi)配額

2010-02-01 09:21:49

GroovyGoogle App Gaelyk

2011-09-06 14:53:01

Google App

2009-04-14 11:01:33

GoogleApp EngineGroovy

2009-04-09 11:06:00

GoogleApp EngineJVM

2012-10-16 09:30:38

谷歌開源云Google App
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)