lucene系列(一)什麼是Lucene

前言

上一個系列尚未完結,我又來開新坑啦~java

接觸搜索/推薦相關工做,也有兩年了。工做裏對lucene的接觸很多,卻也不精。最近工做裏沒有那麼忙,所以想經過學習源碼的方式,來對lucene進行一個系統的學習。apache

此外,聽聞lucene源碼堪稱面對對象設計屆的典範,也想從中吸取一些代碼設計/開發方面的知識。最近總是感受本身寫的代碼有問題,想嘗試優化卻感受很是吃力,常常一頓操做下來提高的頗有限。後端

lucene簡介

如下內容來自維基百科:數組

Lucene是一套用於全文檢索和搜索的開放源碼程序庫,由Apache軟件基金會支持和提供。Lucene提供了一個簡單卻強大的應用程序接口,可以作全文索引和搜索。Lucene是如今最受歡迎的免費Java信息檢索程序庫。微信

全文檢索(Full Text Retrieval)全文檢索是指以所有文本信息做爲檢索對象的一種信息檢索技術。最爲常見的全文檢索搜索引擎就是google和百度了,他們經過對互聯網上的全部網頁內容進行分析,索引,提供給咱們秒級的搜索體驗。其次,當前移動端各類APP,不少都內置了搜索功能,這些也是垂直領域的搜索實現。他們與google/百度的區別就是,只提供當前APP內信息的搜索,而不是互聯網上的全部網頁。markdown

假設有10篇文章,每一篇都有標題和正文。當咱們想找到正文中包含原子能的對應文章時,咱們應該怎麼作?架構

首先,最粗暴的辦法,咱們能夠順序讀取每一篇文章,逐個字符進行判斷,若是其中有連續的三個字符是 原子能,咱們就記錄下來這篇文章的標題,如此所有掃描一遍,咱們就完成了一次搜索。工具

這個方法是至關簡單粗暴,且有效的。在計算機性能十分強勁的狀況下,對於1G的文件進行搜索,均可以使用這個方法(Linux下的grep命令,常用的話應該知道即便在GB級別的文件作些簡單的搜索,一般性能也是能接受的)。oop

可是,數據量會遠大於1G,搜索的要求也更加複雜,不是簡單的字符串匹配,而是多種條件的組合。此時就須要全文搜索了。性能

像google這種搜索引擎,能夠在0.5s的時間,搜索到與"全文搜索引擎"相關的1230w結果,這顯然使用的不是順序的逐個字符對比,而是相似於lucene的全文搜索了。 2020-12-23-22-01-48

lucene能作到在秒級對大量數據進行查詢,依賴的就是被稱之爲索引的結構。對於索引的理解,有不少現成的例子,好比在不少書籍後,都會提供一個關鍵詞到頁碼的映射,這就是一種索引,可讓咱們不用通讀整本書,就能找到本身關心的部分。

在《數學之美》這本書中,做者認爲全文檢索的本質就是布爾代數。隨着對全文檢索的逐漸深刻了解,愈來愈以爲這句話的精準,在全文檢索的索引/搜索階段,根本原理就是最簡單的布爾代數,剩下的只是工程實現的複雜度問題了。

lucene-beta

lucene 目前已經在開發9.0版本了,整個工程分爲多個模塊,十分複雜。

在學習lucene源碼以前,我一直在想,應該以什麼路線去學習lucene,總不能隨機找一個類開始看吧,那樣怕是會陷入細節的汪洋大海中。

最初的想法是,從構建索引開始,走構建索引->寫入磁盤->搜索請求->query分析->相關性打分->返回結果這條路線,逐步學習。

後來忽然產生了一個大膽的想法,我想嘗試抽象全文檢索的本質,寫一個各方面都最簡單的全文檢索工具(最好只有一兩個類的那麼簡單),以後就這個工具的各個方面如何進化成lucene的對應模塊,各類缺陷lucene是如何改進的, 來進行lucene的學習。

這就是這節的標題lucene-beta的來源。

在個人預期中,這樣作應該會有兩個優勢:

  1. 可以更加貼近本質,不至於在局部的細節中迷失。
  2. 從問題推向結論,更加符合情理。可以更加深入的感覺到如此這般的必要性。如無必要,那麼單純炫技又有什麼意思呢?
public class LuceneBeta {
    private static final Logger logger = LoggerFactory.getLogger(LuceneBeta.class);

    public static void main(String[] args) {
        LuceneBeta beta = new LuceneBeta();
        String[] arr = new String[]{"原子能研究所", "原子彈威力很大"};
        Map<Character, int[]> index = beta.build(arr);
        int[] searchRet = beta.search('威', index);
        System.out.println(Arrays.toString(searchRet));
    }

    /** * 對傳入的字符串數組進行字符級別的構建索引 */
    public Map<Character, int[]> build(String[] arr) {
        Set<Character> all = new HashSet<>();
        for (String s : arr) {
            for (char c : s.toCharArray()) {
                all.add(c);
            }
        }
        Map<Character, int[]> index = new HashMap<>();

        for (Character c : all) {
            int[] perContains = new int[arr.length];
            for (int w = 0; w < arr.length; w++) {
                if (arr[w].contains(String.valueOf(c))) {
                    perContains[w] = 1;
                } else {
                    perContains[w] = 0;
                }
            }
            index.put(c, perContains);
        }

        logger.info("build {} strings. indexed: ", arr.length);
        for (Map.Entry<Character, int[]> e : index.entrySet()) {
            logger.info("{} ==> {}", e.getKey(), Arrays.toString(e.getValue()));
        }
        return index;
    }


    /** * 查詢目標字符都在哪些字符串中出現過 */
    public int[] search(char target, Map<Character, int[]> index) {
        if (!index.containsKey(target)) {
            return null;
        }
        int[] ints = index.get(target);
        int[] tmp = new int[index.size()];
        int j = 0;
        for (int i = 0; i < ints.length; i++) {
            if (ints[i] == 1) {
                tmp[j] = i;
                j++;
            }
        }
        int[] ret = new int[j];
        System.arraycopy(tmp, 0, ret, 0, j);
        return ret;
    }

}

複製代碼

說要簡單,那就要簡單到底,所有代碼70行。它實現了什麼功能呢?

在給定的一系列字符串中,能夠搜索某個字符出現的全部字符串編號

google能夠根據你給的關鍵字找到對應的網頁, 上面的代碼能夠根據你提供的關鍵字符,查找對應的字符串, 源碼已經開發了,就等融資上市了,我就是下一個google...

雖然上面的代碼極其簡單,可是爲了後續對應lucene的分析,我仍是要認真的概括其中的每個步驟。

上面的程序中,分爲兩個部分,即兩個方法build 和 search.

首先是build過程:

  1. 遍歷輸入的字符串,拿到全部出現的字符。
  2. 對於每個字符,統計一個字符數組,其中每一位表明當前字符在該編號的字符串中是否出現。1表明出現,0表明未出現。 如"原"在輸入的兩個字符串中均有出現,那麼它對應的統計數組就是[1,1].
  3. 將全部的字符及其統計數組,做爲一份"索引"返回。

search過程

  1. 若是輸入的字符不存在,直接返回空
  2. 取出對應該字符的統計數組,由二進制的表示辦法,還原成原始的字符串編號。
  3. 返回全部出現該字符的字符串編號。

lucene源碼架構介紹

lucene 做爲一個成熟的開源軟件,其包括了多個模塊,其中最核心的是lucene.core包。其中又分爲如下幾個目錄:

2020-12-24-16-21-40

其中:

  • org.apache.lucene.analysis 主要負責詞法分析及語言處理.
  • org.apache.lucene.codecs 主要負責文本內容到倒排索引的編碼和解碼.
  • org.apache.lucene.document 提供了對用戶內容的抽象Document,及Fields.
  • org.apache.lucene.index 主要負責對索引的讀寫。
  • org.apache.lucene.search 主要負責搜索過程。
  • org.apache.lucene.store 主要負責索引的持久化等內容。
  • org.apache.lucene.util 工具包。

結語

本文實現了極簡版的lucene-beta, 固然不是爲了真的替代lucene。只是對全文搜索作一個簡單的抽象,用簡單的功能映射lucene優秀的實現. 逐一的去學習。

最後一個小節簡單的介紹了lucene.core包下的幾個目錄,後續的主要源碼學習,將以lucene-beta中的問題爲引導,分模塊的逐步進行。

lucene 源碼學習,正式開始啦~


完。


聯繫我

最後,歡迎關注個人我的公衆號【 呼延十 】,會不按期更新不少後端工程師的學習筆記。 也歡迎直接公衆號私信或者郵箱聯繫我,必定知無不言,言無不盡。



以上皆爲我的所思所得,若有錯誤歡迎評論區指正。

歡迎轉載,煩請署名並保留原文連接。

聯繫郵箱:huyanshi2580@gmail.com

更多學習筆記見我的博客或關注微信公衆號 <呼延十 >------>呼延十

相關文章
相關標籤/搜索