<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    szhswl
    宋針還的個人空間
    1, 有時對于一個Document來說,有一些Field會被頻繁地操作,而另一些Field則不會。這時可以將頻繁操作的Field和其他Field分開存放,而在搜索時同時檢索這兩部分Field而提取出一個完整的Document。   這要求兩個索引包含的Document的數(shù)量必須相同。
    在創(chuàng)建索引的時候,可以同時創(chuàng)建多個IndexWriter,將一個Document根據(jù)需要拆分成多個包含部分Field的Document,并將這些Document分別添加到不同的索引。
    而在搜索時,則必須借助ParallelReader類來整合。
    Directory dir1=FSDirectory.getDirectory(new File(INDEX_DIR1),false);
    Directory dir2=FSDirectory.getDirectory(new File(INDEX_DIR2),false);
    ParallelReader preader=new ParallelReader();
    preader.add(IndexReader.open(dir1));
    preader.add(IndexReader.open(dir2));

    IndexSearcher searcher=new IndexSearcher(preader);
    之后的操作和一般的搜索相同。

    2, Query的子類. 下面的幾個搜索在各種不同要求的場合,都會用到. 需要大家仔細(xì)研讀!

    Query query1 = new TermQuery(new Term(FieldValue, "name1")); // 詞語搜索
    Query query2 = new WildcardQuery(new Term(FieldName, "name*")); // 通配符
    Query query3 = new PrefixQuery(new Term(FieldName, "name1")); // 字段搜索 Field:Keyword,自動在結(jié)尾添加 *
    Query query4 = new RangeQuery(new Term(FieldNumber, NumberTools.LongToString(11L)), new Term(FieldNumber, NumberTools.LongToString(13L)), true); // 范圍搜索
    Query query5 = new FilteredQuery(query, filter); // 帶過濾條件的搜索
    Query query6 =new MatchAllDocsQuery(... // 用來匹配所有文檔
    Query query7 = new FuzzyQuery (...模糊搜索
    Query query8 = new RegexQuery (..   正則搜索
    Query query9 = new SpanRegexQuery(...)。 同上, 正則表達(dá)式的查詢:
    Query query9 = new SpanQuery 的子類嵌套其他SpanQuery 增加了 rewrite方法
    Query query10 =new DisjunctionMaxQuery () ..類,提供了針對某個短語的最大score。這一點(diǎn)對多字段的搜索非常有用
    Query query11 = new ConstantScoreQuery 類它包裝了一個 filter produces a score
    equal to the query boost for every matching document.

    BooleanQuery query12= new BooleanQuery();
    booleanQuery.add(termQuery 1, BooleanClause.Occur.SHOULD);
    booleanQuery.add(termQuery 2, BooleanClause.Occur.SHOULD);
      //這個是為了聯(lián)合多個查詢而做的Query類. BooleanQuery增加了最小的匹配短語。見:BooleanQuery.setMinimumNumberShouldMatch().


    PhraseQuery
    你可能對中日關(guān)系比較感興趣,想查找‘中’和‘日’挨得比較近(5個字的距離內(nèi))的文章,超過這個距離的不予考慮,你可以:

    PhraseQuery query 13= new PhraseQuery();
    query.setSlop(5);
    query.add(new Term("content ", “中”));
    query.add(new Term(“content”, “日”));

    PhraseQuery對于短語的順序是不管的,這點(diǎn)在查詢時除了提高命中率外,也會對性能產(chǎn)生很大的影響, 利用SpanNearQuery可以對短語的順序進(jìn)行控制,提高性能

    BooleanQuery query12=   new SpanNearQuery 可以對短語的順序進(jìn)行控制,提高性能

    3, 索引文本文件
    如果你想把純文本文件索引起來,而不想自己將它們讀入字符串創(chuàng)建field,你可以用下面的代碼創(chuàng)建field:

    Field field = new Field("content", new FileReader(file));

    這里的file就是該文本文件。該構(gòu)造函數(shù)實(shí)際上是讀去文件內(nèi)容,并對其進(jìn)行索引,但不存儲


    4, 如何刪除索引
    lucene提供了兩種從索引中刪除document的方法,一種是

    void deleteDocument(int docNum)

    這種方法是根據(jù)document在索引中的編號來刪除,每個document加進(jìn)索引后都會有個唯一編號,所以根據(jù)編號刪除是一種精確刪除,但是這個編號是索引的內(nèi)部結(jié)構(gòu),一般我們不會知道某個文件的編號到底是幾,所以用處不大。另一種是

    void deleteDocuments(Term term)

    這種方法實(shí)際上是首先根據(jù)參數(shù)term執(zhí)行一個搜索操作,然后把搜索到的結(jié)果批量刪除了。我們可以通過這個方法提供一個嚴(yán)格的查詢條件,達(dá)到刪除指定document的目的。
    下面給出一個例子:

    Directory dir = FSDirectory.getDirectory(PATH, false);
    IndexReader reader = IndexReader.open(dir);
    Term term = new Term(field, key);
    reader.deleteDocuments(term);
    reader.close();



    5, 如何更新索引
    lucene并沒有提供專門的索引更新方法,我們需要先將相應(yīng)的document刪除,然后再將新的document加入索引。例如:

    Directory dir = FSDirectory.getDirectory(PATH, false);
    IndexReader reader = IndexReader.open(dir);
    Term term = new Term(“title”, “lucene introduction”);
    reader.deleteDocuments(term);
    reader.close();

    IndexWriter writer = new IndexWriter(dir, new StandardAnalyzer(), true);
    Document doc = new Document();
    doc.add(new Field("title", "lucene introduction", Field.Store.YES, Field.Index.TOKENIZED));
    doc.add(new Field("content", "lucene is funny", Field.Store.YES, Field.Index.TOKENIZED));
    writer.addDocument(doc);
    writer.optimize();
    writer.close();


    但是在1.9RC1中說明:
    新增類: org.apache.lucene.index.IndexModifier ,它合并了   IndexWriter 和 IndexReader,好處是我們可以增加和刪除文檔的時候不同擔(dān)心 synchronisation/locking 的問題了。  

    6, filer類.使用 Filter 對搜索結(jié)果進(jìn)行過濾,可以獲得更小范圍內(nèi)更精確的結(jié)果。 有人說: 注意它執(zhí)行的是預(yù)處理,而不是對查詢結(jié)果進(jìn)行過濾,所以使用filter的代價是很大的,它可能會使一次查詢耗時提高一百倍


    ISOLatin1AccentFilter ,用 ISO Latin 1 字符集中的unaccented類字符替代 accented 類字符
    DateFilter   日期過濾器
    RangeFileter ,比 DateFilter 更加通用,實(shí)用
    LengthFilter 類, 已經(jīng)從 contrib 放到了 core 代碼里。從 stream 中去掉太長和太短的單詞   StopFilter 類, 增加了對處理stop words 的忽略大小寫處理


    7,本條是一個使用過濾的說明:

    過濾

    使用 Filter 對搜索結(jié)果進(jìn)行過濾,可以獲得更小范圍內(nèi)更精確的結(jié)果。

    舉個例子,我們搜索上架時間在 2005-10-1 到 2005-10-30 之間的商品。
    對于日期時間,我們需要轉(zhuǎn)換一下才能添加到索引庫,同時還必須是索引字段。
    // index
    document.Add(FieldDate, DateField.DateToString(date), Field.Store.YES, Field.Index.UN_TOKENIZED);

    //...

    // search
    Filter filter = new DateFilter(FieldDate, DateTime.Parse("2005-10-1"), DateTime.Parse("2005-10-30"));
    Hits hits = searcher.Search(query, filter);

    除了日期時間,還可以使用整數(shù)。比如搜索價格在 100 ~ 200 之間的商品。
    Lucene.Net NumberTools 對于數(shù)字進(jìn)行了補(bǔ)位處理,如果需要使用浮點(diǎn)數(shù)可以自己參考源碼進(jìn)行。
    // index
    document.Add(new Field(FieldNumber, NumberTools.LongToString((long)price), Field.Store.YES, Field.Index.UN_TOKENIZED));

    //...

    // search
    Filter filter = new RangeFilter(FieldNumber, NumberTools.LongToString(100L), NumberTools.LongToString(200L), true, true);
    Hits hits = searcher.Search(query, filter);

    使用 Query 作為過濾條件。
    QueryFilter filter = new QueryFilter(QueryParser.Parse("name2", FieldValue, analyzer));

    我們還可以使用 FilteredQuery 進(jìn)行多條件過濾。

    Filter filter = new DateFilter(FieldDate, DateTime.Parse("2005-10-10"), DateTime.Parse("2005-10-15"));
    Filter filter2 = new RangeFilter(FieldNumber, NumberTools.LongToString(11L), NumberTools.LongToString(13L), true, true);

    Query query = QueryParser.Parse("name*", FieldName, analyzer);
    query = new FilteredQuery(query, filter);
    query = new FilteredQuery(query, filter2);

    IndexSearcher searcher = new IndexSearcher(reader);
    Hits hits = searcher.Search(query);



    8, Sort
    有時你想要一個排好序的結(jié)果集,就像SQL語句的“order by”,lucene能做到:通過Sort。
    Sort sort = new Sort(“time”); //相當(dāng)于SQL的“order by time”
    Sort sort = new Sort(“time”, true); // 相當(dāng)于SQL的“order by time desc”
    下面是一個完整的例子:

    Directory dir = FSDirectory.getDirectory(PATH, false);
    IndexSearcher is = new IndexSearcher(dir);
    QueryParser parser = new QueryParser("content", new StandardAnalyzer());
    Query query = parser.parse("title:lucene content:lucene";
    RangeFilter filter = new RangeFilter("time", "20060101", "20060230", true, true);
    Sort sort = new Sort(“time”);
    Hits hits = is.search(query, filter, sort);
    for (int i = 0; i < hits.length(); i++)
    {
    Document doc = hits.doc(i);
    System.out.println(doc.get("title");
    }
    is.close();

    9,   性能優(yōu)化
    一直到這里,我們還是在討論怎么樣使lucene跑起來,完成指定任務(wù)。利用前面說的也確實(shí)能完成大部分功能。但是測試表明lucene的性能并不是很好,在大數(shù)據(jù)量大并發(fā)的條件下甚至?xí)邪敕昼姺祷氐那闆r。另外大數(shù)據(jù)量的數(shù)據(jù)初始化建立索引也是一個十分耗時的過程。那么如何提高lucene的性能呢?下面從優(yōu)化創(chuàng)建索引性能和優(yōu)化搜索性能兩方面介紹。

    9.1 優(yōu)化創(chuàng)建索引性能
    這方面的優(yōu)化途徑比較有限,IndexWriter提供了一些接口可以控制建立索引的操作,另外我們可以先將索引寫入RAMDirectory,再批量寫入FSDirectory,不管怎樣,目的都是盡量少的文件IO,因?yàn)閯?chuàng)建索引的最大瓶頸在于磁盤IO。另外選擇一個較好的分析器也能提高一些性能。

    9.1.1 通過設(shè)置IndexWriter的參數(shù)優(yōu)化索引建立
    setMaxBufferedDocs(int maxBufferedDocs)
    控制寫入一個新的segment前內(nèi)存中保存的document的數(shù)目,設(shè)置較大的數(shù)目可以加快建索引速度,默認(rèn)為10。
    setMaxMergeDocs(int maxMergeDocs)
    控制一個segment中可以保存的最大document數(shù)目,值較小有利于追加索引的速度,默認(rèn)Integer.MAX_VALUE,無需修改。
    setMergeFactor(int mergeFactor)
    控制多個segment合并的頻率,值較大時建立索引速度較快,默認(rèn)是10,可以在建立索引時設(shè)置為100。

    9.1.2 通過RAMDirectory緩寫提高性能
    我們可以先把索引寫入RAMDirectory,達(dá)到一定數(shù)量時再批量寫進(jìn)FSDirectory,減少磁盤IO次數(shù)。

    FSDirectory fsDir = FSDirectory.getDirectory("/data/index", true);
    RAMDirectory ramDir = new RAMDirectory();
    IndexWriter fsWriter = new IndexWriter(fsDir, new StandardAnalyzer(), true);
    IndexWriter ramWriter = new IndexWriter(ramDir, new StandardAnalyzer(), true);
    while (there are documents to index)
    {
    ... create Document ...
    ramWriter.addDocument(doc);
    if (condition for flushing memory to disk has been met)
    {
    fsWriter.addIndexes(new Directory[] { ramDir });
    ramWriter.close();
    ramWriter = new IndexWriter(ramDir, new StandardAnalyzer(), true);
    }
    }

    9.1.3 選擇較好的分析器
    這個優(yōu)化主要是對磁盤空間的優(yōu)化,可以將索引文件減小將近一半,相同測試數(shù)據(jù)下由600M減少到380M。但是對時間并沒有什么幫助,甚至?xí)枰L時間,因?yàn)檩^好的分析器需要匹配詞庫,會消耗更多cpu,測試數(shù)據(jù)用StandardAnalyzer耗時133分鐘;用MMAnalyzer耗時150分鐘。

    9.2 優(yōu)化搜索性能
    雖然建立索引的操作非常耗時,但是那畢竟只在最初創(chuàng)建時才需要,平時只是少量的維護(hù)操作,更何況這些可以放到一個后臺進(jìn)程處理,并不影響用戶搜索。我們創(chuàng)建索引的目的就是給用戶搜索,所以搜索的性能才是我們最關(guān)心的。下面就來探討一下如何提高搜索性能。

    9.2.1 將索引放入內(nèi)存
    這是一個最直觀的想法,因?yàn)閮?nèi)存比磁盤快很多。Lucene提供了RAMDirectory可以在內(nèi)存中容納索引:

    Directory fsDir = FSDirectory.getDirectory(“/data/index/”, false);
    Directory ramDir = new RAMDirectory(fsDir);
    Searcher searcher = new IndexSearcher(ramDir);

    但是實(shí)踐證明RAMDirectory和FSDirectory速度差不多,當(dāng)數(shù)據(jù)量很小時兩者都非常快,當(dāng)數(shù)據(jù)量較大時(索引文件400M)RAMDirectory甚至比FSDirectory還要慢一點(diǎn),這確實(shí)讓人出乎意料。
    而且lucene的搜索非常耗內(nèi)存,即使將400M的索引文件載入內(nèi)存,在運(yùn)行一段時間后都會out of memory,所以個人認(rèn)為載入內(nèi)存的作用并不大。

    9.2.2 優(yōu)化時間范圍限制
    既然載入內(nèi)存并不能提高效率,一定有其它瓶頸,經(jīng)過測試發(fā)現(xiàn)最大的瓶頸居然是時間范圍限制,那么我們可以怎樣使時間范圍限制的代價最小呢?
    當(dāng)需要搜索指定時間范圍內(nèi)的結(jié)果時,可以:
    1、用RangeQuery,設(shè)置范圍,但是RangeQuery的實(shí)現(xiàn)實(shí)際上是將時間范圍內(nèi)的時間點(diǎn)展開,組成一個個BooleanClause加入到BooleanQuery中查詢, 因此時間范圍不可能設(shè)置太大,經(jīng)測試,范圍超過一個月就會拋BooleanQuery.TooManyClauses,可以通過設(shè)置BooleanQuery.setMaxClauseCount(int maxClauseCount)擴(kuò)大,但是擴(kuò)大也是有限的,并且隨著maxClauseCount擴(kuò)大,占用內(nèi)存也擴(kuò)大
    2、用RangeFilter代替RangeQuery,經(jīng)測試速度不會比RangeQuery慢,但是仍然有性能瓶頸,查詢的90%以上時間耗費(fèi)在RangeFilter,研究其源碼發(fā)現(xiàn)RangeFilter實(shí)際上是首先遍歷所有索引,生成一個BitSet,標(biāo)記每個document,在時間范圍內(nèi)的標(biāo)記為true,不在的標(biāo)記為false,然后將結(jié)果傳遞給Searcher查找,這是十分耗時的。
    3、進(jìn)一步提高性能,這個又有兩個思路:
    a、緩存Filter結(jié)果。既然RangeFilter的執(zhí)行是在搜索之前,那么它的輸入都是一定的,就是IndexReader,而IndexReader是由Directory決定的,所以可以認(rèn)為RangeFilter的結(jié)果是由范圍的上下限決定的,也就是由具體的RangeFilter對象決定,所以我們只要以RangeFilter對象為鍵,將filter結(jié)果BitSet緩存起來即可。lucene API已經(jīng)提供了一個CachingWrapperFilter類封裝了Filter及其結(jié)果,所以具體實(shí)施起來我們可以cache CachingWrapperFilter對象,需要注意的是,不要被CachingWrapperFilter的名字及其說明誤導(dǎo),CachingWrapperFilter看起來是有緩存功能,但的緩存是針對同一個filter的,也就是在你用同一個filter過濾不同IndexReader時,它可以幫你緩存不同IndexReader的結(jié)果,而我們的需求恰恰相反,我們是用不同filter過濾同一個IndexReader,所以只能把它作為一個封裝類。
    b、降低時間精度。研究Filter的工作原理可以看出,它每次工作都是遍歷整個索引的,所以時間粒度越大,對比越快,搜索時間越短,在不影響功能的情況下,時間精度越低越好,有時甚至犧牲一點(diǎn)精度也值得,當(dāng)然最好的情況是根本不作時間限制。
    下面針對上面的兩個思路演示一下優(yōu)化結(jié)果(都采用800線程隨機(jī)關(guān)鍵詞隨即時間范圍):
    第一組,時間精度為秒:
    方式 直接用RangeFilter 使用cache 不用filter
    平均每個線程耗時 10s 1s 300ms

    第二組,時間精度為天
    方式 直接用RangeFilter 使用cache 不用filter
    平均每個線程耗時 900ms 360ms 300ms

    由以上數(shù)據(jù)可以得出結(jié)論:
    1、 盡量降低時間精度,將精度由秒換成天帶來的性能提高甚至比使用cache還好,最好不使用filter。
    2、 在不能降低時間精度的情況下,使用cache能帶了10倍左右的性能提高。

    9.2.3 使用更好的分析器
    這個跟創(chuàng)建索引優(yōu)化道理差不多,索引文件小了搜索自然會加快。當(dāng)然這個提高也是有限的。較好的分析器相對于最差的分析器對性能的提升在20%以下。

    10 一些經(jīng)驗(yàn)

    10.1關(guān)鍵詞區(qū)分大小寫
    or AND TO等關(guān)鍵詞是區(qū)分大小寫的,lucene只認(rèn)大寫的,小寫的當(dāng)做普通單詞。

    10.2 讀寫互斥性
    同一時刻只能有一個對索引的寫操作,在寫的同時可以進(jìn)行搜索

    10.3 文件鎖
    在寫索引的過程中強(qiáng)行退出將在tmp目錄留下一個lock文件,使以后的寫操作無法進(jìn)行,可以將其手工刪除

    10.4 時間格式
    lucene只支持一種時間格式y(tǒng)yMMddHHmmss,所以你傳一個yy-MM-dd HH:mm:ss的時間給lucene它是不會當(dāng)作時間來處理的

    10.5 設(shè)置boost
    有些時候在搜索時某個字段的權(quán)重需要大一些,例如你可能認(rèn)為標(biāo)題中出現(xiàn)關(guān)鍵詞的文章比正文中出現(xiàn)關(guān)鍵詞的文章更有價值,你可以把標(biāo)題的boost設(shè)置的更大,那么搜索結(jié)果會優(yōu)先顯示標(biāo)題中出現(xiàn)關(guān)鍵詞的文章(沒有使用排序的前題下)。使用方法:
    Field. setBoost(float boost);默認(rèn)值是1.0,也就是說要增加權(quán)重的需要設(shè)置得比1大。

    上面這篇關(guān)于性能的講解是很深刻. 請學(xué)習(xí).

    本文轉(zhuǎn)自:http://zhangxinzhou.blog.ccidnet.com/blog-htm-do-showone-uid-36421-type-blog-itemid-213713.html


    ---------------------------------------------------------------------------------------------------------------------------------
    說人之短,乃護(hù)己之短。夸己之長,乃忌人之長。皆由存心不厚,識量太狹耳。能去此弊,可以進(jìn)德,可以遠(yuǎn)怨。
    http://m.tkk7.com/szhswl
    ------------------------------------------------------------------------------------------------------ ----------------- ---------
    posted on 2007-12-17 19:36 宋針還 閱讀(413) 評論(0)  編輯  收藏 所屬分類: 搜索引擎
    主站蜘蛛池模板: 亚洲中文字幕丝袜制服一区| 久久国产亚洲观看| 久久嫩草影院免费看夜色| 亚洲香蕉成人AV网站在线观看| 爱丫爱丫影院在线观看免费| 亚洲性一级理论片在线观看| 国产zzjjzzjj视频全免费| 久草免费福利视频| 亚洲日韩看片无码电影| 亚洲人成色77777| 在线观看免费高清视频| av午夜福利一片免费看久久| 久久久久亚洲AV无码网站| 国产精品视_精品国产免费 | 成全视频免费观看在线看| 亚洲国产精品免费观看 | 日本亚洲国产一区二区三区| 一级女人18毛片免费| 一区二区三区免费在线观看| 亚洲日本国产乱码va在线观看| 国产hs免费高清在线观看| 久久99国产乱子伦精品免费| 国产成人+综合亚洲+天堂| 久久久久亚洲AV无码网站| 国产成人亚洲精品91专区手机| 在线观看的免费网站| 久久青草免费91线频观看不卡| 美女视频黄频a免费| 亚洲日本香蕉视频观看视频| 中文亚洲成a人片在线观看| 天天摸夜夜摸成人免费视频| 一区二区三区在线免费看| 免费又黄又爽又猛大片午夜 | 一个人看的www免费高清| 自拍偷区亚洲国内自拍| 亚洲午夜视频在线观看| 亚洲一级特黄大片在线观看 | 亚洲Av无码国产情品久久 | 亚洲成人精品久久| 老司机亚洲精品影视www| 国产免费久久精品久久久|