11潭苞、自定義過(guò)濾器(lucene筆記)

一忽冻、概述

在查詢的過(guò)程中,如果我們想然某些索引不被查詢到此疹,可以將相關(guān)索引刪除僧诚,但是刪除后如果在后面又需要讓其被查詢,這樣需要重建索引蝗碎,這樣反反復(fù)復(fù)顯然很麻煩湖笨。 于是我們可以自定義過(guò)濾器,控制部分查詢權(quán)限蹦骑。自定義過(guò)濾器原理其實(shí)很簡(jiǎn)單慈省,就是為每個(gè)索引再創(chuàng)建一個(gè)標(biāo)記,此標(biāo)記只能是0或者1眠菇,當(dāng)一個(gè)索引的標(biāo)記為0時(shí)這個(gè)索引是不會(huì)被查詢到的边败,反之則可以。所有的索引的標(biāo)記就像一個(gè)bit序列一樣捎废。

二笑窜、入門(mén)(工程lucene_filter0

首先我們?cè)诠ぞ哳?lèi)FileIndexUtil.java中創(chuàng)建索引的方法中添加一個(gè)字段索引。

public static void index(boolean hasNew) {
    IndexWriter writer = null;
    try {
        writer = new IndexWriter(directory, new IndexWriterConfig(
                Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));
        if (hasNew) {
            writer.deleteAll();//如果我們要新建索引登疗,那么將之前創(chuàng)建的刪除
        }
        File file = new File("E:/myeclipse/Lucene/somefile");

        Document document = null;
        Random random = new Random();
        int index = 0;//這里為id創(chuàng)建一個(gè)索引
        for (File f : file.listFiles()) {
            //將每個(gè)索引的評(píng)分設(shè)置成一個(gè)隨機(jī)數(shù)
            int score = random.nextInt(600);
            document = new Document();

            document.add(new Field("id", String.valueOf(index++), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

            document.add(new Field("content", new FileReader(f)));
            document.add(new Field("filename", f.getName(),
                    Field.Store.YES, Field.Index.NOT_ANALYZED));
            document.add(new Field("path", f.getAbsolutePath(),
                    Field.Store.YES, Field.Index.NOT_ANALYZED));
            document.add(new NumericField("date", Field.Store.YES, true)
                    .setLongValue(f.lastModified()));
            // 最后我們將字節(jié)數(shù)轉(zhuǎn)換成kb
            document.add(new NumericField("size", Field.Store.YES, true)
                    .setIntValue((int) (f.length())));
            //這里我們使用score評(píng)分來(lái)創(chuàng)建索引排截,沒(méi)有存儲(chǔ)嫌蚤,搜索出來(lái)的時(shí)候?yàn)閚ull
            //這里我自己隨機(jī)設(shè)置的一個(gè)評(píng)分
            document.add(new NumericField("score", Field.Store.NO, true).setIntValue(score));
            writer.addDocument(document);
        }
    } catch (CorruptIndexException e) {
        e.printStackTrace();
    } catch (LockObtainFailedException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (writer != null) {
            try {
                writer.close();
            } catch (CorruptIndexException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

說(shuō)明:可以看到這里我們添加了id的索引。然后重建索引断傲。

定義一個(gè)查詢方法類(lèi):
CustomFilter.java

package cn.itcast.util;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;

public class CustomFilter {
    public void searchByCustomFilter(){
        try {
            IndexSearcher searcher = new IndexSearcher(IndexReader.open(FileIndexUtil.getDirectory()));
            Query q = new TermQuery(new Term("content", "java"));
            TopDocs tds = null;
            tds = searcher.search(q, new MyIdFilter(), 100);
            for (ScoreDoc sd : tds.scoreDocs) {
                Document doc = searcher.doc(sd.doc);
                System.out.println("id:" + sd.doc + "脱吱,評(píng)分:" + sd.score 
                        + ",名稱(chēng):" + doc.get("filename") + "认罩,路徑:" + doc.get("path")
                        + "急凰,文件大小:" + doc.get("size")
                        + ", bit id: " + doc.get("id"));
            }
            searcher.close();
        } catch (CorruptIndexException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

自定義過(guò)濾器MyIdFilter.java

package cn.itcast.util;
import java.io.IOException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermDocs;
import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.Filter;
import org.apache.lucene.util.OpenBitSet;

public class MyIdFilter extends Filter {
    
    //存儲(chǔ)要?jiǎng)h除的id
    private String[] delIds = {"10"};
    
    @Override
    public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
        
        //這就相當(dāng)于為每個(gè)索引創(chuàng)建一個(gè)標(biāo)記猜年,比如設(shè)置標(biāo)記為0不顯示,設(shè)置為1顯示疾忍,這樣就達(dá)到了過(guò)濾的效果乔外。
        //此對(duì)象創(chuàng)建好之后所有對(duì)象都是0
        OpenBitSet obs = new OpenBitSet(reader.maxDoc());
        //obs.set(5);//將doc id設(shè)置為1
        //先把元素填滿,該文檔的對(duì)應(yīng)元素就會(huì)被設(shè)置為1
        obs.set(0, reader.maxDoc() - 1);
        int[] docs = new int[1];//存放位置
        int[] freqs = new int[1];//次數(shù)
        //獲取id所在的位置并且將其設(shè)置為0
        for(String delId : delIds){
            //獲取TermDocs
            TermDocs tds = reader.termDocs(new Term("id", delId));
            //會(huì)將查詢出來(lái)的對(duì)象的位置存儲(chǔ)到docs中,出現(xiàn)的頻率存儲(chǔ)在freqs一罩,返回查詢出來(lái)的條數(shù)
            int count = tds.read(docs, freqs);
            if(count == 1){//本來(lái)也只有一條數(shù)據(jù)
                obs.clear(docs[0]);//將這個(gè)位置的元素刪除
            }
        }
        return obs;
    }
}

測(cè)試TestCustomFilter.java

@Test
public void test01(){
    CustomFilter filter = new CustomFilter();
    filter.searchByCustomFilter();
}

說(shuō)明:可以看到在CustomFiltet.java中我們?cè)趧?chuàng)建搜索的時(shí)候?qū)⒆远x過(guò)濾器傳遞進(jìn)去了杨幼。這樣就可以實(shí)現(xiàn)過(guò)濾查詢。測(cè)試結(jié)果:

1

可以看到我們將id為10的索引給過(guò)濾掉了聂渊。但是這種寫(xiě)法顯然不是很好差购,比如這里將要過(guò)濾的索引的id都寫(xiě)死了。

三汉嗽、改進(jìn)(工程lucene_filter1

這里我們首先編寫(xiě)一個(gè)接口FilterAccessor.java欲逃,此接口專(zhuān)門(mén)用來(lái)設(shè)置我們要處理的域、域相關(guān)的值饼暑、是否要處理稳析。

package cn.itcast.util;

//這里存儲(chǔ)過(guò)濾器要處理的內(nèi)容,之前我們是寫(xiě)死的
public interface FilterAccessor {
    
    public String[] values();//要處理的值弓叛,比如id值
    
    public String getField();//表示要處理的域彰居,比如id
    
    public boolean set();//是否要進(jìn)行處理(將值設(shè)置進(jìn)去)
}

說(shuō)明:這里的是否要處理的意思是,如果我們將一些id值設(shè)置進(jìn)去撰筷,就表示我們只想讓這些id索引被查詢到陈惰。將其他的沒(méi)有設(shè)置的索引過(guò)濾掉。

MyIdFilter.java

package cn.itcast.util;
import java.io.IOException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermDocs;
import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.Filter;
import org.apache.lucene.util.OpenBitSet;

public class MyIdFilter extends Filter {

    // 存儲(chǔ)要?jiǎng)h除的id
    private FilterAccessor accessor;

    public MyIdFilter(FilterAccessor accessor) {
        this.accessor = accessor;
    }

    @Override
    public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
        OpenBitSet obs = new OpenBitSet(reader.maxDoc());
        if(accessor.set()){
            set(reader, obs);
        }else {
            clear(reader, obs);
        }
        return obs;
    }

    private void set(IndexReader reader, OpenBitSet obs) {
        try {
            int[] docs = new int[1];
            int[] freqs = new int[1];
            for (String delId : accessor.values()) {
                TermDocs tds = reader.termDocs(new Term(accessor.getField(), delId));
                int count = tds.read(docs, freqs);
                if (count == 1) {
                    obs.set(docs[0]);//讓標(biāo)記為1
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void clear(IndexReader reader, OpenBitSet obs) {
        try {
            obs.set(0, reader.maxDoc() - 1);
            int[] docs = new int[1];
            int[] freqs = new int[1];
            for (String delId : accessor.values()) {
                TermDocs tds = reader.termDocs(new Term(accessor.getField(), delId));
                int count = tds.read(docs, freqs);
                if (count == 1) {
                    obs.clear(docs[0]);//讓標(biāo)記為0
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

說(shuō)明:從這里可以看到毕籽,我們會(huì)將傳遞進(jìn)來(lái)的值對(duì)應(yīng)的索引的標(biāo)記設(shè)置為1抬闯,讓其被查詢到。否則設(shè)置標(biāo)記為0关筒,這樣便不能被查詢到画髓。

在類(lèi)CustomFilter.java中我們將相關(guān)的值傳遞進(jìn)來(lái):

public void searchByCustomFilter(){
    try {
        IndexSearcher searcher = new IndexSearcher(IndexReader.open(FileIndexUtil.getDirectory()));
        Query q = new TermQuery(new Term("content", "java"));
        TopDocs tds = null;
        tds = searcher.search(q, new MyIdFilter(new FilterAccessor() {
            //設(shè)置要處理的域的值逐沙,也就是我只想讓下面的索引被查詢到
            @Override
            public String[] values() {
                //return new String[]{"1", "5", "10"};
                return new String[]{"json.config", "json.ini", "json.ssh"};
            }
            //true表示要進(jìn)行過(guò)濾處理
            @Override
            public boolean set() {
                return true;
            }
            //設(shè)置要處理的域
            @Override
            public String getField() {
                //return "id";
                return "filename";
            }
        }), 100);
        for (ScoreDoc sd : tds.scoreDocs) {
            Document doc = searcher.doc(sd.doc);
            System.out.println("id:" + sd.doc + "馒稍,評(píng)分:" + sd.score 
                    + "祖今,名稱(chēng):" + doc.get("filename") + ",路徑:" + doc.get("path")
                    + "更米,文件大小:" + doc.get("size")
                    + ", bit id: " + doc.get("id"));
        }
        searcher.close();
    } catch (CorruptIndexException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

說(shuō)明:這里我們是使用了一個(gè)內(nèi)部類(lèi)辽慕,其實(shí)更好的做法是為每個(gè)域創(chuàng)建相關(guān)的實(shí)現(xiàn)類(lèi)酬核。然后傳遞進(jìn)來(lái)。然后再次進(jìn)行測(cè)試碉纳。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末勿负,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子劳曹,更是在濱河造成了極大的恐慌奴愉,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铁孵,死亡現(xiàn)場(chǎng)離奇詭異锭硼,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)蜕劝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén)檀头,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人岖沛,你說(shuō)我怎么就攤上這事暑始。” “怎么了婴削?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵廊镜,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我唉俗,道長(zhǎng)期升,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任互躬,我火速辦了婚禮播赁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吼渡。我一直安慰自己容为,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開(kāi)白布寺酪。 她就那樣靜靜地躺著坎背,像睡著了一般。 火紅的嫁衣襯著肌膚如雪寄雀。 梳的紋絲不亂的頭發(fā)上得滤,一...
    開(kāi)封第一講書(shū)人閱讀 51,287評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音盒犹,去河邊找鬼懂更。 笑死眨业,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的沮协。 我是一名探鬼主播龄捡,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼慷暂!你這毒婦竟也來(lái)了聘殖?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤行瑞,失蹤者是張志新(化名)和其女友劉穎奸腺,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體血久,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡突照,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了洋魂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡喜鼓,死狀恐怖副砍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情庄岖,我是刑警寧澤豁翎,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站隅忿,受9級(jí)特大地震影響心剥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜背桐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一优烧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧链峭,春花似錦畦娄、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至励饵,卻和暖如春驳癌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背役听。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工颓鲜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留表窘,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓灾杰,卻偏偏與公主長(zhǎng)得像蚊丐,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子艳吠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理麦备,服務(wù)發(fā)現(xiàn),斷路器昭娩,智...
    卡卡羅2017閱讀 134,654評(píng)論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,807評(píng)論 6 342
  • ¥開(kāi)啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開(kāi)一個(gè)線程凛篙,因...
    小菜c閱讀 6,404評(píng)論 0 17
  • 還記得小時(shí)候家附近有一家小型的酒坊呛梆,那濃香的酒味彌漫在周?chē)目臻g中。感覺(jué)它很特別磕诊,所以我有事沒(méi)事也會(huì)去看一下他...
    詩(shī)he遠(yuǎn)方閱讀 455評(píng)論 1 1
  • 今天是5月20號(hào)霎终,這一天本就普普通通的周六滞磺,和其他日子一樣沒(méi)什么特別。 就是因?yàn)?20三個(gè)數(shù)字讓人覺(jué)得有紀(jì)念意義在...
    阿行PPT閱讀 512評(píng)論 0 1