全文檢索 — Lucene_01(全文檢索介紹、Lucene全文檢索流程、創建索引入門程序、查詢索引入門程序、luke的簡單使用)


歡迎訪問筆者個人技術博客:http://rukihuang.xyz/

一、什麼是全文檢索

1.1 數據的分類

1.1.1 結構化數據

  • 格式固定、長度固定、數據類型固定
    • 如:數據庫中的數據

1.1.2 非結構化數據

  • 格式不固定、長度不固定、數據類型不固定
    • word文檔、pdf文檔、郵件、html、txt

1.2 數據的查詢

1.2.1 結構化數據的查詢

  • SQL語句
    • 簡單、數據快

1.2.2 非結構化數據的查詢

  • 需求:從文本文件中找出包含特定單詞的文件
    • 目測
    • 順序掃描。使用程序將文件讀取到內存中,隨後匹配字符串。
    • 把非結構化數據轉換爲結構化數據
    • 先依據空格進行字符串拆分,得到一個單詞列表,基於單詞列表創建一個索引。
      然後查詢索引,分局單詞和文檔的對應關係找到文檔列表,這就是全文檢索。
      • 索引:一個爲了提高查詢速度,創建某種數據結構的集合。

1.3 全文檢索

  • 先創建索引,然後查詢索引的過程叫做全文索引。
    • 索引一次創建可以多次使用。

二、全文檢索的應用場景

  • 只要是有搜索的地方,就可以使用全文檢索技術。

2.1 搜索引擎

  • 百度
  • 360
  • 谷歌

2.2 站內搜索

  • 論壇搜索
  • 微博
  • 文章搜索

2.3 電商搜索

  • 淘寶搜索
  • 京東搜索

三、什麼是Lucene

  • Lucene是一個基於java開發的全文檢索工具包
  • Lucene是apache軟件基金會4 jakarta項目組的一個子項目,是一個開放源代碼的全文檢索引擎工具包,但它不是一個完整的全文檢索引擎,而是一個全文檢索引擎的架構,提供了完整的查詢引擎和索引引擎,部分文本分析引擎(英文與德文兩種西方語言)。Lucene的目的是爲軟件開發人員提供一個簡單易用的工具包,以方便的在目標系統中實現全文檢索的功能,或者是以此爲基礎建立起完整的全文檢索引擎。Lucene是一套用於全文檢索和搜尋的開源程式庫,由Apache軟件基金會支持和提供。Lucene提供了一個簡單卻強大的應用程式接口,能夠做全文索引和搜尋。在Java開發環境裏Lucene是一個成熟的免費開源工具。就其本身而言,Lucene是當前以及最近幾年最受歡迎的免費Java信息檢索程序庫。人們經常提到信息檢索程序庫,雖然與搜索引擎有關,但不應該將信息檢索程序庫與搜索引擎相混淆。

四、 Lucene實現全文檢索的流程

在這裏插入圖片描述

4.1 創建索引

4.1.1 獲得文檔

  • 原始文檔:要基於哪些數據來進行搜索,那麼這些搜索對象就是原始文檔。
    • 搜索引擎:使用爬蟲獲得原始文檔
    • 站內搜索:對數據庫中的數據進行查找。
    • 案例:直接使用io流讀取磁盤上的文件。

4.1.2 構建文檔對象

  • 對應每個原始文檔創建一個Document
  • 每個Document對象中包含多個域(Field),域中保存的就是原始文檔數據。

在這裏插入圖片描述

  • 每個文檔都有一個唯一的編號,就是文檔id

4.1.3 分析文檔

  • 分詞的過程。(案例)
    1. 根據空格進行字符串的拆分
    2. 把單詞統一轉換成小寫
    3. 去除標點符號
    4. 去除停用詞(無意義的詞)
  • 每個關鍵詞都封裝成一個Term對象
    • Term包含兩部分的內容
      • 關鍵詞所在的域
      • 關鍵詞本身
    • 不同的域中拆分出來的相同的關鍵詞是不同Term

4.1.4 創建索引

  • 基於關鍵詞列表創建一個索引,保存到索引庫中
  • 索引庫(三部分內容):
    • 索引
    • document對象
    • 關鍵詞和文檔的對應關係

在這裏插入圖片描述

  • 創建索引是對語彙單元索引,通過詞語找文檔,這種索引的結構叫做倒排索引結構
    • 倒排索引,也叫反向索引結構,包括索引和文檔兩部分,索引即詞彙表,它的規模較小,而文檔集合較大。

在這裏插入圖片描述

  • 傳統方法是根據文件找到文件的該內容,在文件內容中匹配搜索的關鍵字,這種方式是順序掃描方法,數據量大、搜索慢。

4.2 查詢索引

4.2.1 用戶查詢接口

  • 用戶輸入查詢條件的地方
    • 如:百度的搜索框

4.2.2 把關鍵詞封裝成一個查詢對象

  • 要查詢的域
  • 要搜索的關鍵詞

4.2.3 執行查詢

  • 根據要查詢的關鍵詞到對應的域上進行搜索
  • 找到關鍵詞,根據關鍵詞找到對應的文檔

4.2.4 渲染結果

  • 根據文檔的結果,找到文檔對象,對關鍵詞進行高亮顯示,分頁處理,頁面展示。

五、入門程序

5.1 創建索引

5.1.1 創建環境

  • 下載Lucene,jdk最低要求1.8

5.1.2 工程搭建

  • 添加jar包
    • lucene-analyzers-common-8.3.0.jar
    • lucene-core-8.3.0.jar
    • commons-io.jar

5.1.3 步驟

  1. 創建一個Directory對象,指定索引庫保存的位置。
  2. 基於Directory對象創建一個IndexWriter對象
  3. 讀取磁盤上的文件,對應每個文件創建一個文檔對象
  4. 向文檔對象中添加域
  5. 把文檔對象寫入索引庫
  6. 關閉IndexWriter對象
    @Test
    public void createIndex() throws Exception {
        //1. 創建一個Directory對象,指定索引庫保存的位置。
        //把索引庫保存在內存中
        //Directory directory = new RAMDirectory();
        //把索引庫保存在磁盤中
        Directory directory = FSDirectory.open(new File("F:\\lucenetest\\index").toPath());
        //2. 基於Directory對象創建一個IndexWriter對象
        IndexWriter indexWriter = new IndexWriter(directory, new IndexWriterConfig());
        //3. 讀取磁盤上的文件,對應每個we年創建一個文檔對象
        File dir = new File("F:\\Java\\12-lucene\\02.參考資料\\searchsource");
        File[] files = dir.listFiles();
        for (File file : files) {
            //獲取文件名
            String fileName = file.getName();
            //獲取文件路徑
            String filePath = file.getPath();
            //獲取文件內容
            String fileContent = FileUtils.readFileToString(file, "utf-8");
            //獲取文集大小
            long fileSize = FileUtils.sizeOf(file);
            //創建Field
            //參數1:域的名稱;參數2:域的內容;參數3:是否存儲
            Field fieldName = new TextField("name", fileName, Field.Store.YES);
            Field fieldPath = new TextField("path", filePath, Field.Store.YES);
            Field fieldContent = new TextField("content", fileContent, Field.Store.YES);
            Field fieldSize = new TextField("size", fileSize + "", Field.Store.YES);
            //創建文檔對象
            Document document = new Document();

        //4. 向文檔對象中添加域
            document.add(fieldName);
            document.add(fieldPath);
            document.add(fieldContent);
            document.add(fieldSize);
        //5. 把文檔對象寫入索引庫
            indexWriter.addDocument(document);
        }

        //6. 關閉indexwriter對象
        indexWriter.close();
    }

5.2 使用luke查看索引庫中的內容

  • luke的版本必須和Lucene的版本相同才能進行可視化查看。

在這裏插入圖片描述

5.3 查詢索引庫

5.3.1 步驟

  1. 創建一個Director對象,指定索引庫的位置
  2. 創建一個IndexReader對象
  3. 創建一個IndexSearcher對象,構造方法中的參數indexReader對象
  4. 創建一個Query對象,TermQuery
  5. 執行查詢,得到一個TopDocs對象
  6. 取查詢結果的總記錄數
  7. 取文檔列表
  8. 打印文檔中的內容
  9. 關閉IndexReader對象
	@Test
    public void searchIndex() throws Exception {
        //1. 創建一個`Director`對象,指定索引庫的位置
        Directory directory = FSDirectory.open(new File("F:\\lucenetest\\index").toPath());
        //2. 創建一個`IndexReader`對象
        IndexReader indexReader = DirectoryReader.open(directory);
        //3. 創建一個`IndexSearcher`對象,構造方法中的參數`indexReader`對象
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);
        //4. 創建一個`Query`對象,`TermQuery`
        Query query = new TermQuery(new Term("content", "spring"));//在content域中,找spring這個關鍵字
        //5. 執行查詢,得到一個`TopDocs`對象
        //參數1:查詢對象;參數2:查詢結果返回的最大記錄數
        TopDocs topDocs = indexSearcher.search(query, 10);
        //6. 取查詢結果的總記錄數
        System.out.println(topDocs.totalHits);
        //7. 取文檔列表
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        //8. 打印文檔中的內容
        for (ScoreDoc scoreDoc : scoreDocs) {
            //取文檔id
            int docId = scoreDoc.doc;
            //根據id取文檔對象
            Document document = indexSearcher.doc(docId);
            System.out.println(document.get("name"));
            System.out.println(document.get("path"));
            System.out.println(document.get("size"));
            System.out.println(document.get("content"));
            System.out.println("----------------");
        }
        //9. 關閉`IndexReader`對象
        indexReader.close();
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章