亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

Lucene就是這么簡(jiǎn)單

xeblog / 1984人閱讀

摘要:那我們現(xiàn)在是不知道記錄是否真真正正存儲(chǔ)到索引庫(kù)中的,因?yàn)槲覀兛床灰姟K饕龓?kù)存放的數(shù)據(jù)放在文件下,我們也是不能打開文件的。

什么是Lucene??
Lucene是apache軟件基金會(huì)發(fā)布的一個(gè)開放源代碼的全文檢索引擎工具包,由資深全文檢索專家Doug Cutting所撰寫,它是一個(gè)全文檢索引擎的架構(gòu),提供了完整的創(chuàng)建索引和查詢索引,以及部分文本分析的引擎,Lucene的目的是為軟件開發(fā)人員提供一個(gè)簡(jiǎn)單易用的工具包,以方便在目標(biāo)系統(tǒng)中實(shí)現(xiàn)全文檢索的功能,或者是以此為基礎(chǔ)建立起完整的全文檢索引擎,Lucene在全文檢索領(lǐng)域是一個(gè)經(jīng)典的祖先,現(xiàn)在很多檢索引擎都是在其基礎(chǔ)上創(chuàng)建的,思想是相通的。

Lucene是根據(jù)關(guān)健字來(lái)搜索的文本搜索工具,只能在某個(gè)網(wǎng)站內(nèi)部搜索文本內(nèi)容,不能跨網(wǎng)站搜索

既然談到了網(wǎng)站內(nèi)部的搜索,那么我們就談?wù)勎覀兪煜さ陌俣取oogle那些搜索引擎又是基于什么搜索的呢....

從圖上已經(jīng)看得很清楚,baidu、google等搜索引擎其實(shí)是通過(guò)網(wǎng)絡(luò)爬蟲的程序來(lái)進(jìn)行搜索的...

為什么我們要用Lucene?

在介紹Lucene的時(shí)候,我們已經(jīng)說(shuō)了:Lucene又不是搜索引擎,僅僅是在網(wǎng)站內(nèi)部進(jìn)行文本的搜索。那我們?yōu)槭裁匆獙W(xué)他呢???

我們之前編寫納稅服務(wù)系統(tǒng)的時(shí)候,其實(shí)就已經(jīng)使用過(guò)SQL來(lái)進(jìn)行站內(nèi)的搜索..

既然SQL能做的功能,我們還要學(xué)Lucene,為什么呢???

我們來(lái)看看我們用SQL來(lái)搜索的話,有什么缺點(diǎn):

(1)SQL只能針對(duì)數(shù)據(jù)庫(kù)表搜索,不能直接針對(duì)硬盤上的文本搜索

(2)SQL沒(méi)有相關(guān)度排名

(3)SQL搜索結(jié)果沒(méi)有關(guān)健字高亮顯示

(4)SQL需要數(shù)據(jù)庫(kù)的支持,數(shù)據(jù)庫(kù)本身需要內(nèi)存開銷較大,例如:Oracle

(5)SQL搜索有時(shí)較慢,尤其是數(shù)據(jù)庫(kù)不在本地時(shí),超慢,例如:Oracle

我們來(lái)看看在baidu中搜索Lucene為關(guān)鍵字搜索出的內(nèi)容是怎么樣的:

以上所說(shuō)的,我們?nèi)绻褂肧QL的話,是做不到的。因此我們就學(xué)習(xí)Lucene來(lái)幫我們?cè)谡緝?nèi)根據(jù)文本關(guān)鍵字來(lái)進(jìn)行搜索數(shù)據(jù)

我們?nèi)绻W(wǎng)站需要根據(jù)關(guān)鍵字來(lái)進(jìn)行搜索,可以使用SQL,也可以使用Lucene...那么我們Lucene和SQL是一樣的,都是在持久層中編寫代碼的。。

一、快速入門

接下來(lái),我們就講解怎么使用Lucene了.....在講解Lucene的API之前,我們首先來(lái)講講Lucene存放的究竟是什么內(nèi)容...我們的SQL使用的是數(shù)據(jù)庫(kù)中的內(nèi)存,在硬盤中為DBF文件...那么我們Lucene內(nèi)部又是什么東西呢??

Lucene中存的就是一系列的二進(jìn)制壓縮文件和一些控制文件,它們位于計(jì)算機(jī)的硬盤上,
這些內(nèi)容統(tǒng)稱為索引庫(kù),索引庫(kù)有二部份組成:

(1)原始記錄

存入到索引庫(kù)中的原始文本,例如:我是鐘福成

(2)詞匯表

按照一定的拆分策略(即分詞器)將原始記錄中的每個(gè)字符拆開后,存入一個(gè)供將來(lái)搜索的表

也就是說(shuō):Lucene存放數(shù)據(jù)的地方我們通常稱之為索引庫(kù),索引庫(kù)又分為兩部分組成:原始記錄和詞匯表....

1.1原始記錄和詞匯表

當(dāng)我們想要把數(shù)據(jù)存到索引庫(kù)的時(shí)候,我們首先存入的是將數(shù)據(jù)存到原始記錄上面去....

又由于我們給用戶使用的時(shí)候,用戶使用的是關(guān)鍵字來(lái)進(jìn)行查詢我們的具體記錄。因此,我們需要把我們原始存進(jìn)的數(shù)據(jù)進(jìn)行拆分!將拆分出來(lái)的數(shù)據(jù)存進(jìn)詞匯表中。

詞匯表就是類似于我們?cè)趯W(xué)Oracle中的索引表,拆分的時(shí)候會(huì)給出對(duì)應(yīng)的索引值。

一旦用戶根據(jù)關(guān)鍵字來(lái)進(jìn)行搜索,那么程序就先去查詢?cè)~匯表中有沒(méi)有該關(guān)鍵字,如果有該關(guān)鍵字就定位到原始記錄表中,將符合條件的原始記錄返回給用戶查看。

我們查看以下的圖方便理解:

到了這里,有人可能就會(huì)疑問(wèn):難道原始記錄拆分的數(shù)據(jù)都是一個(gè)一個(gè)漢字進(jìn)行拆分的嗎??然后在詞匯表中不就有很多的關(guān)鍵字了???

其實(shí),我們?cè)诖娴皆加涗洷碇械臅r(shí)候,可以指定我們使用哪種算法來(lái)將數(shù)據(jù)拆分,存到詞匯表中.....我們的圖是Lucene的標(biāo)準(zhǔn)分詞算法,一個(gè)一個(gè)漢字進(jìn)行拆分。我們可以使用別的分詞算法,兩個(gè)兩個(gè)拆分或者其他的算法。

1.2編寫第一個(gè)Lucene程序

首先,我們來(lái)導(dǎo)入Lucene的必要開發(fā)包:

lucene-core-3.0.2.jar【Lucene核心】

lucene-analyzers-3.0.2.jar【分詞器】

lucene-highlighter-3.0.2.jar【Lucene會(huì)將搜索出來(lái)的字,高亮顯示,提示用戶】

lucene-memory-3.0.2.jar【索引庫(kù)優(yōu)化策略】

創(chuàng)建User對(duì)象,User對(duì)象封裝了數(shù)據(jù)....

/**
 * Created by ozc on 2017/7/12.
 */
public class User {


    private String id ;
    private String userName;
    private String sal;

    public User() {

    }
    public User(String id, String userName, String sal) {
        this.id = id;
        this.userName = userName;
        this.sal = sal;
    }
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getSal() {
        return sal;
    }

    public void setSal(String sal) {
        this.sal = sal;
    }
}

我們想要使用Lucene來(lái)查詢出站內(nèi)的數(shù)據(jù),首先我們得要有個(gè)索引庫(kù)吧!于是我們先創(chuàng)建索引庫(kù),將我們的數(shù)據(jù)存到索引庫(kù)中

創(chuàng)建索引庫(kù)的步驟:

1)創(chuàng)建JavaBean對(duì)象

2)創(chuàng)建Docment對(duì)象

3)將JavaBean對(duì)象所有的屬性值,均放到Document對(duì)象中去,屬性名可以和JavaBean相同或不同

4)創(chuàng)建IndexWriter對(duì)象

5)將Document對(duì)象通過(guò)IndexWriter對(duì)象寫入索引庫(kù)中

6)關(guān)閉IndexWriter對(duì)象

    @Test
    public void createIndexDB() throws Exception {

        //把數(shù)據(jù)填充到JavaBean對(duì)象中
        User user = new User("1", "鐘福成", "未來(lái)的程序員");

        //創(chuàng)建Document對(duì)象【導(dǎo)入的是Lucene包下的Document對(duì)象】
        Document document = new Document();

        //將JavaBean對(duì)象所有的屬性值,均放到Document對(duì)象中去,屬性名可以和JavaBean相同或不同


        /**
         * 向Document對(duì)象加入一個(gè)字段
         * 參數(shù)一:字段的關(guān)鍵字
         * 參數(shù)二:字符的值
         * 參數(shù)三:是否要存儲(chǔ)到原始記錄表中
         *      YES表示是
         *      NO表示否
         * 參數(shù)四:是否需要將存儲(chǔ)的數(shù)據(jù)拆分到詞匯表中
         *      ANALYZED表示拆分
         *      NOT_ANALYZED表示不拆分
         *
         * */
        document.add(new Field("id", user.getId(), Field.Store.YES, Field.Index.ANALYZED));
        document.add(new Field("userName", user.getUserName(), Field.Store.YES, Field.Index.ANALYZED));
        document.add(new Field("sal", user.getSal(), Field.Store.YES, Field.Index.ANALYZED));

        //創(chuàng)建IndexWriter對(duì)象
        //目錄指定為E:/createIndexDB
        Directory directory = FSDirectory.open(new File("E:/createIndexDB"));

        //使用標(biāo)準(zhǔn)的分詞算法對(duì)原始記錄表進(jìn)行拆分
        Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);

        //LIMITED默認(rèn)是1W個(gè)
        IndexWriter.MaxFieldLength maxFieldLength = IndexWriter.MaxFieldLength.LIMITED;
        /**
         * IndexWriter將我們的document對(duì)象寫到硬盤中
         *
         * 參數(shù)一:Directory d,寫到硬盤中的目錄路徑是什么
         * 參數(shù)二:Analyzer a, 以何種算法來(lái)對(duì)document中的原始記錄表數(shù)據(jù)進(jìn)行拆分成詞匯表
         * 參數(shù)三:MaxFieldLength mfl 最多將文本拆分出多少個(gè)詞匯
         *
         * */
        IndexWriter indexWriter = new IndexWriter(directory, analyzer, maxFieldLength);

        //將Document對(duì)象通過(guò)IndexWriter對(duì)象寫入索引庫(kù)中
        indexWriter.addDocument(document);

        //關(guān)閉IndexWriter對(duì)象
        indexWriter.close();

    }

程序執(zhí)行完,我們就會(huì)在硬盤中見到我們的索引庫(kù)。

那我們現(xiàn)在是不知道記錄是否真真正正存儲(chǔ)到索引庫(kù)中的,因?yàn)槲覀兛床灰?。索引?kù)存放的數(shù)據(jù)放在cfs文件下,我們也是不能打開cfs文件的

于是,我們現(xiàn)在用一個(gè)關(guān)鍵字,把索引庫(kù)的數(shù)據(jù)讀取??纯醋x取數(shù)據(jù)是否成功。

根據(jù)關(guān)鍵字查詢索引庫(kù)中的內(nèi)容:

1)創(chuàng)建IndexSearcher對(duì)象

2)創(chuàng)建QueryParser對(duì)象

3)創(chuàng)建Query對(duì)象來(lái)封裝關(guān)鍵字

4)用IndexSearcher對(duì)象去索引庫(kù)中查詢符合條件的前100條記錄,不足100條記錄的以實(shí)際為準(zhǔn)

5)獲取符合條件的編號(hào)

6)用indexSearcher對(duì)象去索引庫(kù)中查詢編號(hào)對(duì)應(yīng)的Document對(duì)象

7)將Document對(duì)象中的所有屬性取出,再封裝回JavaBean對(duì)象中去,并加入到集合中保存,以備將之用

    @Test
    public void findIndexDB() throws Exception {

        /**
         * 參數(shù)一: IndexSearcher(Directory path)查詢以xxx目錄的索引庫(kù)
         *
         * */
        Directory directory = FSDirectory.open(new File("E:/createIndexDB"));
        //創(chuàng)建IndexSearcher對(duì)象
        IndexSearcher indexSearcher = new IndexSearcher(directory);

        //創(chuàng)建QueryParser對(duì)象
        /**
         * 參數(shù)一: Version matchVersion 版本號(hào)【和上面是一樣的】
         * 參數(shù)二:String f,【要查詢的字段】
         * 參數(shù)三:Analyzer a【使用的拆詞算法】
         * */
        Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
        QueryParser queryParser = new QueryParser(Version.LUCENE_30, "userName", analyzer);

        //給出要查詢的關(guān)鍵字
        String keyWords = "鐘";

        //創(chuàng)建Query對(duì)象來(lái)封裝關(guān)鍵字
        Query query = queryParser.parse(keyWords);

        //用IndexSearcher對(duì)象去索引庫(kù)中查詢符合條件的前100條記錄,不足100條記錄的以實(shí)際為準(zhǔn)
        TopDocs topDocs = indexSearcher.search(query, 100);

        //獲取符合條件的編號(hào)

        for (int i = 0; i < topDocs.scoreDocs.length; i++) {

            ScoreDoc scoreDoc = topDocs.scoreDocs[i];
            int no = scoreDoc.doc;
            //用indexSearcher對(duì)象去索引庫(kù)中查詢編號(hào)對(duì)應(yīng)的Document對(duì)象
            Document document = indexSearcher.doc(no);

            //將Document對(duì)象中的所有屬性取出,再封裝回JavaBean對(duì)象中去
            String id = document.get("id");
            String userName = document.get("userName");
            String sal = document.get("sal");

            User user = new User(id, userName, sal);
            System.out.println(user);
            
        }

效果:

1.3進(jìn)一步說(shuō)明Lucene代碼

我們的Lucene程序就是大概這么一個(gè)思路:將JavaBean對(duì)象封裝到Document對(duì)象中,然后通過(guò)IndexWriter把document寫入到索引庫(kù)中。當(dāng)用戶需要查詢的時(shí)候,就使用IndexSearcher從索引庫(kù)中讀取數(shù)據(jù),找到對(duì)應(yīng)的Document對(duì)象,從而解析里邊的內(nèi)容,再封裝到JavaBean對(duì)象中讓我們使用。

二、對(duì)Lucene代碼優(yōu)化

我們?cè)俅慰椿匚覀兩弦黄焖偃腴T寫過(guò)的代碼,我來(lái)截取一些有代表性的:

以下代碼在把數(shù)據(jù)填充到索引庫(kù),和從索引庫(kù)查詢數(shù)據(jù)的時(shí)候,都出現(xiàn)了。是重復(fù)代碼!

        Directory directory = FSDirectory.open(new File("E:/createIndexDB"));

        //使用標(biāo)準(zhǔn)的分詞算法對(duì)原始記錄表進(jìn)行拆分
        Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);

以下的代碼其實(shí)就是將JavaBean的數(shù)據(jù)封裝到Document對(duì)象中,我們是可以通過(guò)反射來(lái)對(duì)其進(jìn)行封裝....如果不封裝的話,我們?nèi)绻泻芏郕avaBean都要添加到Document對(duì)象中,就會(huì)出現(xiàn)很多類似的代碼。

          document.add(new Field("id", user.getId(), Field.Store.YES, Field.Index.ANALYZED));
        document.add(new Field("userName", user.getUserName(), Field.Store.YES, Field.Index.ANALYZED));
        document.add(new Field("sal", user.getSal(), Field.Store.YES, Field.Index.ANALYZED));

以下代碼就是從Document對(duì)象中把數(shù)據(jù)取出來(lái),封裝到JavaBean去。如果JavaBean中有很多屬性,也是需要我們寫很多次類似代碼....


            //將Document對(duì)象中的所有屬性取出,再封裝回JavaBean對(duì)象中去
            String id = document.get("id");
            String userName = document.get("userName");
            String sal = document.get("sal");
             User user = new User(id, userName, sal);
2.1編寫Lucene工具類

在編寫工具類的時(shí)候,值得注意的地方:

當(dāng)我們得到了對(duì)象的屬性的時(shí)候,就可以把屬性的get方法封裝起來(lái)

得到get方法,就可以調(diào)用它,得到對(duì)應(yīng)的值

在操作對(duì)象的屬性時(shí),我們要使用暴力訪問(wèn)

如果有屬性,值,對(duì)象這三個(gè)變量,我們記得使用BeanUtils組件

import org.apache.commons.beanutils.BeanUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.junit.Test;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * Created by ozc on 2017/7/12.
 */

/**
 * 使用單例事例模式
 * */
public class LuceneUtils {
    private static Directory directory;
    private static Analyzer analyzer;
    private static IndexWriter.MaxFieldLength maxFieldLength;

    private LuceneUtils() {}

    static{
        try {
            directory = FSDirectory.open(new File("E:/createIndexDB"));
            analyzer = new StandardAnalyzer(Version.LUCENE_30);
            maxFieldLength = IndexWriter.MaxFieldLength.LIMITED;
        } catch (Exception e) {
            e.printStackTrace();

        }
    }

    public static Directory getDirectory() {
        return directory;
    }

    public static Analyzer getAnalyzer() {
        return analyzer;
    }

    public static IndexWriter.MaxFieldLength getMaxFieldLength() {
        return maxFieldLength;
    }

    /**
     * @param object 傳入的JavaBean類型
     * @return 返回Document對(duì)象
     */
    public static Document javaBean2Document(Object object) {
        try {
            Document document = new Document();
            //得到JavaBean的字節(jié)碼文件對(duì)象
            Class aClass = object.getClass();

            //通過(guò)字節(jié)碼文件對(duì)象得到對(duì)應(yīng)的屬性【全部的屬性,不能僅僅調(diào)用getFields()】
            Field[] fields = aClass.getDeclaredFields();

            //得到每個(gè)屬性的名字
            for (Field field : fields) {
                String name = field.getName();
                //得到屬性的值【也就是調(diào)用getter方法獲取對(duì)應(yīng)的值】
                String method = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
                //得到對(duì)應(yīng)的值【就是得到具體的方法,然后調(diào)用就行了。因?yàn)槭莋et方法,沒(méi)有參數(shù)】
                Method aClassMethod = aClass.getDeclaredMethod(method, null);
                String value = aClassMethod.invoke(object).toString();
                System.out.println(value);


                //把數(shù)據(jù)封裝到Document對(duì)象中。
                document.add(new org.apache.lucene.document.Field(name, value, org.apache.lucene.document.Field.Store.YES, org.apache.lucene.document.Field.Index.ANALYZED));
            }
            return document;
        }  catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * @param aClass   要解析的對(duì)象類型,要用戶傳入進(jìn)來(lái)
     * @param document 將Document對(duì)象傳入進(jìn)來(lái)
     * @return 返回一個(gè)JavaBean
     */
    public static Object Document2JavaBean(Document document, Class aClass) {
        try {
            //創(chuàng)建該JavaBean對(duì)象
            Object obj = aClass.newInstance();
            //得到該JavaBean所有的成員變量
            Field[] fields = aClass.getDeclaredFields();
            for (Field field : fields) {

                //設(shè)置允許暴力訪問(wèn)
                field.setAccessible(true);
                String name = field.getName();
                String value = document.get(name);
                //使用BeanUtils把數(shù)據(jù)封裝到Bean中
                BeanUtils.setProperty(obj, name, value);
            }
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    @Test
    public void test() {
        User user = new User();
        LuceneUtils.javaBean2Document(user);
    }
    
}
2.2使用LuceneUtils改造程序
    @Test
    public void createIndexDB() throws Exception {
        //把數(shù)據(jù)填充到JavaBean對(duì)象中
        User user = new User("2", "鐘福成2", "未來(lái)的程序員2");
        Document document = LuceneUtils.javaBean2Document(user);
        /**
         * IndexWriter將我們的document對(duì)象寫到硬盤中
         *
         * 參數(shù)一:Directory d,寫到硬盤中的目錄路徑是什么
         * 參數(shù)二:Analyzer a, 以何種算法來(lái)對(duì)document中的原始記錄表數(shù)據(jù)進(jìn)行拆分成詞匯表
         * 參數(shù)三:MaxFieldLength mfl 最多將文本拆分出多少個(gè)詞匯
         *
         * */
        IndexWriter indexWriter = new IndexWriter(LuceneUtils.getDirectory(), LuceneUtils.getAnalyzer(), LuceneUtils.getMaxFieldLength());

        //將Document對(duì)象通過(guò)IndexWriter對(duì)象寫入索引庫(kù)中
        indexWriter.addDocument(document);
        //關(guān)閉IndexWriter對(duì)象
        indexWriter.close();
    }


    @Test
    public void findIndexDB() throws Exception {


        //創(chuàng)建IndexSearcher對(duì)象
        IndexSearcher indexSearcher = new IndexSearcher(LuceneUtils.getDirectory());
        //創(chuàng)建QueryParser對(duì)象
        QueryParser queryParser = new QueryParser(Version.LUCENE_30, "userName", LuceneUtils.getAnalyzer());
        //給出要查詢的關(guān)鍵字
        String keyWords = "鐘";
        //創(chuàng)建Query對(duì)象來(lái)封裝關(guān)鍵字
        Query query = queryParser.parse(keyWords);
        //用IndexSearcher對(duì)象去索引庫(kù)中查詢符合條件的前100條記錄,不足100條記錄的以實(shí)際為準(zhǔn)
        TopDocs topDocs = indexSearcher.search(query, 100);
        //獲取符合條件的編號(hào)
        for (int i = 0; i < topDocs.scoreDocs.length; i++) {
            ScoreDoc scoreDoc = topDocs.scoreDocs[i];
            int no = scoreDoc.doc;
            //用indexSearcher對(duì)象去索引庫(kù)中查詢編號(hào)對(duì)應(yīng)的Document對(duì)象
            Document document = indexSearcher.doc(no);
            //將Document對(duì)象中的所有屬性取出,再封裝回JavaBean對(duì)象中去
            User user = (User) LuceneUtils.Document2JavaBean(document, User.class);
            System.out.println(user);

        }
    }

三、索引庫(kù)優(yōu)化

我們已經(jīng)可以創(chuàng)建索引庫(kù)并且從索引庫(kù)讀取對(duì)象的數(shù)據(jù)了。其實(shí)索引庫(kù)還有地方可以優(yōu)化的....

3.1合并文件

我們把數(shù)據(jù)添加到索引庫(kù)中的時(shí)候,每添加一次,都會(huì)幫我們自動(dòng)創(chuàng)建一個(gè)cfs文件...

這樣其實(shí)不好,因?yàn)槿绻麛?shù)據(jù)量一大,我們的硬盤就有非常非常多的cfs文件了.....其實(shí)索引庫(kù)會(huì)幫我們自動(dòng)合并文件的,默認(rèn)是10個(gè)。

如果,我們想要修改默認(rèn)的值,我們可以通過(guò)以下的代碼修改:

//索引庫(kù)優(yōu)化
indexWriter.optimize();

//設(shè)置合并因子為3,每當(dāng)有3個(gè)cfs文件,就合并
indexWriter.setMergeFactor(3);

3.2設(shè)置內(nèi)存索引庫(kù)

我們的目前的程序是直接與文件進(jìn)行操作,這樣對(duì)IO的開銷其實(shí)是比較大的。而且速度相對(duì)較慢....我們可以使用內(nèi)存索引庫(kù)來(lái)提高我們的讀寫效率...

對(duì)于內(nèi)存索引庫(kù)而言,它的速度是很快的,因?yàn)槲覀冎苯硬僮鲀?nèi)存...但是呢,我們要將內(nèi)存索引庫(kù)是要到硬盤索引庫(kù)中保存起來(lái)的。當(dāng)我們讀取數(shù)據(jù)的時(shí)候,先要把硬盤索引庫(kù)的數(shù)據(jù)同步到內(nèi)存索引庫(kù)中去的。

        Article article = new Article(1,"培訓(xùn)","傳智是一家Java培訓(xùn)機(jī)構(gòu)");
        Document document = LuceneUtil.javabean2document(article);
        
        Directory fsDirectory = FSDirectory.open(new File("E:/indexDBDBDBDBDBDBDBDB"));
        Directory ramDirectory = new RAMDirectory(fsDirectory);
        
        IndexWriter fsIndexWriter = new IndexWriter(fsDirectory,LuceneUtil.getAnalyzer(),true,LuceneUtil.getMaxFieldLength());
        IndexWriter ramIndexWriter = new IndexWriter(ramDirectory,LuceneUtil.getAnalyzer(),LuceneUtil.getMaxFieldLength());
        
        ramIndexWriter.addDocument(document);
        ramIndexWriter.close();
        
        fsIndexWriter.addIndexesNoOptimize(ramDirectory);
        fsIndexWriter.close();
四、分詞器

我們?cè)谇懊嬷芯鸵呀?jīng)說(shuō)過(guò)了,在把數(shù)據(jù)存到索引庫(kù)的時(shí)候,我們會(huì)使用某些算法,將原始記錄表的數(shù)據(jù)存到詞匯表中.....那么這些算法總和我們可以稱之為分詞器

分詞器: 采用一種算法,將中英文本中的字符拆分開來(lái),形成詞匯,以待用戶輸入關(guān)健字后搜索

對(duì)于為什么要使用分詞器,我們也明確地說(shuō)過(guò):由于用戶不可能把我們的原始記錄數(shù)據(jù)完完整整地記錄下來(lái),于是他們?cè)谒阉鞯臅r(shí)候,是通過(guò)關(guān)鍵字進(jìn)行對(duì)原始記錄表的查詢....此時(shí),我們就采用分詞器來(lái)最大限度地匹配相關(guān)的數(shù)據(jù)

4.1分詞器流程

步一:按分詞器拆分出詞匯

步二:去除停用詞和禁用詞

步三:如果有英文,把英文字母轉(zhuǎn)為小寫,即搜索不分大小寫

4.2分詞器API

我們?cè)谶x擇分詞算法的時(shí)候,我們會(huì)發(fā)現(xiàn)有非常非常多地分詞器API,我們可以用以下代碼來(lái)看看該分詞器是怎么將數(shù)據(jù)分割的

    private static void testAnalyzer(Analyzer analyzer, String text) throws Exception {
        System.out.println("當(dāng)前使用的分詞器:" + analyzer.getClass());
        TokenStream tokenStream = analyzer.tokenStream("content",new StringReader(text));
        tokenStream.addAttribute(TermAttribute.class);
        while (tokenStream.incrementToken()) {
            TermAttribute termAttribute = tokenStream.getAttribute(TermAttribute.class);
            System.out.println(termAttribute.term());
        }
    }

在實(shí)驗(yàn)完之后,我們就可以選擇恰當(dāng)?shù)姆衷~算法了....

4.3IKAnalyzer分詞器

這是一個(gè)第三方的分詞器,我們?nèi)绻褂玫脑捫枰獙?dǎo)入對(duì)應(yīng)的jar包

IKAnalyzer3.2.0Stable.jar

步二:將IKAnalyzer.cfg.xml和stopword.dic和xxx.dic文件復(fù)制到MyEclipse的src目錄下,再進(jìn)行配置,在配置時(shí),首行需要一個(gè)空行

這個(gè)第三方的分詞器有什么好呢????他是中文首選的分詞器...也就是說(shuō):他是按照中文的詞語(yǔ)來(lái)進(jìn)行拆分的!

五、對(duì)搜索結(jié)果進(jìn)行處理 5.1搜索結(jié)果高亮

我們?cè)谑褂肧QL時(shí),搜索出來(lái)的數(shù)據(jù)是沒(méi)有高亮的...而我們使用Lucene,搜索出來(lái)的內(nèi)容我們可以設(shè)置關(guān)鍵字為高亮...這樣一來(lái)就更加注重用戶體驗(yàn)了!

        String keywords = "鐘福成";
        List
articleList = new ArrayList
(); QueryParser queryParser = new QueryParser(LuceneUtil.getVersion(),"content",LuceneUtil.getAnalyzer()); Query query = queryParser.parse(keywords); IndexSearcher indexSearcher = new IndexSearcher(LuceneUtil.getDirectory()); TopDocs topDocs = indexSearcher.search(query,1000000); //設(shè)置關(guān)鍵字高亮 Formatter formatter = new SimpleHTMLFormatter("",""); Scorer scorer = new QueryScorer(query); Highlighter highlighter = new Highlighter(formatter,scorer); for(int i=0;i 5.2搜索結(jié)果摘要

如果我們搜索出來(lái)的文章內(nèi)容太大了,而我們只想顯示部分的內(nèi)容,那么我們可以對(duì)其進(jìn)行摘要...

值得注意的是:搜索結(jié)果摘要需要與設(shè)置高亮一起使用

String keywords = "鐘福成";
        List
articleList = new ArrayList
(); QueryParser queryParser = new QueryParser(LuceneUtil.getVersion(),"content",LuceneUtil.getAnalyzer()); Query query = queryParser.parse(keywords); IndexSearcher indexSearcher = new IndexSearcher(LuceneUtil.getDirectory()); TopDocs topDocs = indexSearcher.search(query,1000000); Formatter formatter = new SimpleHTMLFormatter("",""); Scorer scorer = new QueryScorer(query); Highlighter highlighter = new Highlighter(formatter,scorer); //設(shè)置摘要 Fragmenter fragmenter = new SimpleFragmenter(4); highlighter.setTextFragmenter(fragmenter); for(int i=0;i 5.3搜索結(jié)果排序

我們搜索引擎肯定用得也不少,使用不同的搜索引擎來(lái)搜索相同的內(nèi)容。他們首頁(yè)的排行順序也會(huì)不同...這就是它們內(nèi)部用了搜索結(jié)果排序....

影響網(wǎng)頁(yè)的排序有非常多種:

head/meta/【keywords關(guān)鍵字】

網(wǎng)頁(yè)的標(biāo)簽整潔

網(wǎng)頁(yè)執(zhí)行速度

采用div+css

等等等等

而在Lucene中我們就可以設(shè)置相關(guān)度得分來(lái)使不同的結(jié)果對(duì)其進(jìn)行排序:

        IndexWriter indexWriter = new IndexWriter(LuceneUtil.getDirectory(),LuceneUtil.getAnalyzer(),LuceneUtil.getMaxFieldLength());
        //為結(jié)果設(shè)置得分
        document.setBoost(20F);
        indexWriter.addDocument(document);
        indexWriter.close();

當(dāng)然了,我們也可以按單個(gè)字段排序:

    //true表示降序
    Sort sort = new Sort(new SortField("id",SortField.INT,true));
    TopDocs topDocs = indexSearcher.search(query,null,1000000,sort);

也可以按多個(gè)字段排序:在多字段排序中,只有第一個(gè)字段排序結(jié)果相同時(shí),第二個(gè)字段排序才有作用 提倡用數(shù)值型排序

        Sort sort = new Sort(new SortField("count",SortField.INT,true),new SortField("id",SortField.INT,true));
        TopDocs topDocs = indexSearcher.search(query,null,1000000,sort);
5.4條件搜索

在我們的例子中,我們使用的是根據(jù)一個(gè)關(guān)鍵字來(lái)對(duì)某個(gè)字段的內(nèi)容進(jìn)行搜索。語(yǔ)法類似于下面:

    QueryParser queryParser = new QueryParser(LuceneUtil.getVersion(),"content",LuceneUtil.getAnalyzer());
    

其實(shí),我們也可以使用關(guān)鍵字來(lái)對(duì)多個(gè)字段進(jìn)行搜索,也就是多條件搜索。我們實(shí)際中常常用到的是多條件搜索,多條件搜索可以使用我們最大限度匹配對(duì)應(yīng)的數(shù)據(jù)

QueryParser queryParser = new MultiFieldQueryParser(LuceneUtil.getVersion(),new String[]{"content","title"},LuceneUtil.getAnalyzer());
六、總結(jié)

Lucene是全文索引引擎的祖先,后面的Solr、Elasticsearch都是基于Lucene的(后面會(huì)有一篇講Elasticsearch的,敬請(qǐng)期待~)

Lucene中存的就是一系列的二進(jìn)制壓縮文件和一些控制文件,這些內(nèi)容統(tǒng)稱為索引庫(kù),索引庫(kù)又分了兩個(gè)部分:

原始記錄

詞匯表

了解索引庫(kù)的優(yōu)化方式:1、合并文件 2、設(shè)置內(nèi)存索引庫(kù)

Lucene的分詞器有非常多種,選擇自己適合的一種進(jìn)行分詞

查詢出來(lái)的結(jié)果可對(duì)其設(shè)置高亮、摘要、排序

這篇這是Lucene的冰山一角,一般現(xiàn)在用的可能都是Solr、Elasticsearch的了,但想要更加深入了解Lucene可翻閱其他資料哦~

如果文章有錯(cuò)的地方歡迎指正,大家互相交流。習(xí)慣在微信看技術(shù)文章,想要獲取更多的Java資源的同學(xué),可以關(guān)注微信公眾號(hào):Java3y

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/68847.html

相關(guān)文章

  • Lucene就是這么容易

    摘要:就其本身而言,是當(dāng)前以及最近幾年最受歡迎的免費(fèi)信息檢索程序庫(kù)。這樣完全和數(shù)據(jù)庫(kù)進(jìn)行了隔離。當(dāng)一個(gè)文檔出現(xiàn)在了搜索結(jié)果中,這就意味著該文檔與用戶給定的查詢語(yǔ)句是相匹配的。 showImg(https://segmentfault.com/img/bVbuifx?w=258&h=258);公眾號(hào)閱讀https://mp.weixin.qq.com/s/M3... Lucene [TOC] ...

    894974231 評(píng)論0 收藏0
  • Lucene 構(gòu)建文檔數(shù)據(jù)庫(kù)

    摘要:說(shuō)到檔案系統(tǒng),選文檔數(shù)據(jù)庫(kù)再合適不過(guò)了。熟悉的人看這個(gè)會(huì)很眼熟,沒(méi)錯(cuò),這就是從借鑒過(guò)來(lái),并用在我的關(guān)系數(shù)據(jù)庫(kù)查詢上。接口規(guī)范接口的主要目是為了傳遞數(shù)據(jù),數(shù)據(jù)結(jié)構(gòu)已經(jīng)在上面給出。為便于不同系統(tǒng)不同終端的數(shù)據(jù)交換,也將應(yīng)當(dāng)在接口支持之內(nèi)。 說(shuō)到檔案系統(tǒng),選文檔數(shù)據(jù)庫(kù)再合適不過(guò)了。談到文檔數(shù)據(jù)庫(kù)一般想到的是 MongoDB、CouchDB 之類的,可這里要說(shuō)的不是這些,而是另一個(gè) NoSQL...

    inapt 評(píng)論0 收藏0
  • Lucene 構(gòu)建文檔數(shù)據(jù)庫(kù)

    摘要:說(shuō)到檔案系統(tǒng),選文檔數(shù)據(jù)庫(kù)再合適不過(guò)了。熟悉的人看這個(gè)會(huì)很眼熟,沒(méi)錯(cuò),這就是從借鑒過(guò)來(lái),并用在我的關(guān)系數(shù)據(jù)庫(kù)查詢上。接口規(guī)范接口的主要目是為了傳遞數(shù)據(jù),數(shù)據(jù)結(jié)構(gòu)已經(jīng)在上面給出。為便于不同系統(tǒng)不同終端的數(shù)據(jù)交換,也將應(yīng)當(dāng)在接口支持之內(nèi)。 說(shuō)到檔案系統(tǒng),選文檔數(shù)據(jù)庫(kù)再合適不過(guò)了。談到文檔數(shù)據(jù)庫(kù)一般想到的是 MongoDB、CouchDB 之類的,可這里要說(shuō)的不是這些,而是另一個(gè) NoSQL...

    zhangyucha0 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<