1. 程式人生 > >Apache Lucene全域性搜尋引擎入門教程

Apache Lucene全域性搜尋引擎入門教程

Lucene簡介

Lucent:Apache軟體基金會Jakarta專案組的一個子專案,Lucene提供了一個簡單卻強大的應用程式介面,能夠做全文索引和搜尋。在Java開發環境裡Lucene是一個成熟的免費開源工具。就其本身而言,Lucene是當前以及最近幾年最受歡迎的免費Java資訊檢索程式庫。 —— [ 百度百科 ]

資料庫索引和Lucene檢索對比

比較項 Lucene檢索 資料庫檢索
資料檢索 從Lucene的索引檔案中檢出 由資料庫索引檢索記錄
索引結構 Document(文件) Record(記錄)
全文檢索 支援 不支援
模糊查詢 支援 不支援
結果排序 支援排序 不能排序

Lucene搜尋的API類主要有4個 IndexSearch,Query,QueryParser,Hits

Lucene搜尋過程

Lucene的索引結構是文件(Document)形式的,下面簡單介紹一下Lucene搜尋的過程
(1)將文件傳給分片語件(Tokenizer),分片語件根據標點符號和停詞將文件分成詞元(Token),並將標點符號和停詞去掉。

停詞是指沒有特別意思的詞。英語的是指比如a、the等等單詞

文章1內容:Tom favorite fruit is apple.

經過分詞處理後,變成[Tom][facorite][fruit][apple]

(2)再將詞元傳給語言處理元件(Linguistic Processor)

英語的單詞經過語言處理元件處理後,字母變為小寫,詞元會變成最基本的詞根形式,比如likes變成like

經過分詞處理後,變成[tom][favorite][fruit][apple]

(3) 然後得到的詞元傳給索引元件(Indexer),索引元件處理得到索引結構,得到關鍵字、出現頻率、出現位置分別作為詞典檔案(Term Dictionary)、頻率檔案(frequencies)和位置檔案(positions)儲存起來,然後通過二元搜尋演算法快速查詢關鍵字

關鍵字 文章號[出現頻率] 出現位置
tom 1[1] 1
favorite 1[2] 2
fruit 1[3] 3

[apple| 1[4] | 4 |

Lucene簡單例項

建立一個Maven專案,在pom.xml加入Lucene所需的jar

<dependencies>
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-core</artifactId>
            <version>5.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-analyzers-common</artifactId>
            <version>5.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-queryparser</artifactId>
            <version>5.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-analyzers-smartcn</artifactId>
            <version>5.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-highlighter</artifactId>
            <version>5.3.1</version>
        </dependency>
    </dependencies>

建立索引的簡單例項

package com.demo.lucene;


import java.io.IOException;
import java.nio.file.Paths;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;


/**
 * <pre>
 *  Lucene建立索引服務類
 * </pre>
 *
 * @author nicky
 * @version 1.00.00
 *
 *          <pre>
 * 修改記錄
 *    修改後版本:     修改人:  修改日期:2018年04月18日     修改內容:
 *          </pre>
 */
@Component
public class LuceneIndexer {

    private volatile static LuceneIndexer instance;

    private final static String INDEX_DIR = "D:\\lucene";

    private static class SingletonHolder{
        private final static LuceneIndexer instance=new LuceneIndexer();
    }

    public static LuceneIndexer getInstance(){
        return SingletonHolder.instance;
    }

    public boolean createIndex(String indexDir) throws IOException{
        //加點測試的靜態資料
        Integer ids[] = {1 , 2 , 3};
        String titles[] = {"標題1" , "標題2" , "標題3"};
        String tcontents[] = {
                "內容1內容啊哈哈哈",
                "內容2內容啊哈哈哈",
                "內容3內容啊哈哈哈"
        };

        long startTime = System.currentTimeMillis();//記錄索引開始時間

        Analyzer analyzer = new SmartChineseAnalyzer();
        Directory directory = FSDirectory.open(Paths.get(indexDir));
        IndexWriterConfig config = new IndexWriterConfig(analyzer);

        IndexWriter indexWriter = new IndexWriter(directory, config);

        for(int i = 0; i < ids.length;i++){
            Document doc = new Document();
            //新增欄位
            doc.add(new IntField("id", ids[i],Field.Store.YES)); //新增內容
            doc.add(new TextField("title", titles[i], Field.Store.YES)); //新增檔名,並把這個欄位存到索引檔案裡
            doc.add(new TextField("tcontent", tcontents[i], Field.Store.YES)); //新增檔案路徑
            indexWriter.addDocument(doc);
        }

        indexWriter.commit();
        System.out.println("共索引了"+indexWriter.numDocs()+"個檔案");
        indexWriter.close();
        System.out.println("建立索引所用時間:"+(System.currentTimeMillis()-startTime)+"毫秒");

        return true;
    }

    public static void main(String[] args) {
        try {
            boolean r = LuceneIndexer.getInstance().createIndex(INDEX_DIR);
            if(r){
                System.out.println("索引建立成功!");
            }else{
                System.out.println("索引建立失敗!");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

全域性搜尋索引

package com.demo.lucene;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.highlight.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

import java.io.IOException;
import java.io.StringReader;
import java.nio.file.Paths;


/**
 * <pre>
 *  Lucene全域性搜尋服務類
 * </pre>
 *
 * @author nicky
 * @version 1.00.00
 *
 *          <pre>
 * 修改記錄
 *    修改後版本:     修改人:  修改日期:2018年04月18日     修改內容:
 *          </pre>
 */
public class SearchBuilder {

    public static void doSearch(String indexDir , String queryStr) throws IOException, ParseException, InvalidTokenOffsetsException {
        Directory directory = FSDirectory.open(Paths.get(indexDir));
        DirectoryReader reader = DirectoryReader.open(directory);
        IndexSearcher searcher = new IndexSearcher(reader);
        Analyzer analyzer = new SmartChineseAnalyzer();
        QueryParser parser = new QueryParser("tcontent",analyzer);
        Query query = parser.parse(queryStr);

        long startTime = System.currentTimeMillis();
        TopDocs docs = searcher.search(query,10);

        System.out.println("查詢"+queryStr+"所用時間:"+(System.currentTimeMillis()-startTime));
        System.out.println("查詢到"+docs.totalHits+"條記錄");


        //遍歷查詢結果
        for(ScoreDoc scoreDoc : docs.scoreDocs){
            Document doc = searcher.doc(scoreDoc.doc);
            String tcontent = doc.get("tcontent");
            if(tcontent != null){
                TokenStream tokenStream =  analyzer.tokenStream("tcontent", new StringReader(tcontent));
                String summary = highlighter.getBestFragment(tokenStream, tcontent);
                System.out.println(summary);
            }
        }
        reader.close();
    }

    public static void main(String[] args){
        String indexDir = "D:\\lucene";
        String q = "內容"; //查詢這個字串
        try {
            doSearch(indexDir, q);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

加入高亮顯示:

public class SearchBuilder {

    public static void doSearch(String indexDir , String queryStr) throws IOException, ParseException, InvalidTokenOffsetsException {
        Directory directory = FSDirectory.open(Paths.get(indexDir));
        DirectoryReader reader = DirectoryReader.open(directory);
        IndexSearcher searcher = new IndexSearcher(reader);
        Analyzer analyzer = new SmartChineseAnalyzer();
        QueryParser parser = new QueryParser("tcontent",analyzer);
        Query query = parser.parse(queryStr);

        long startTime = System.currentTimeMillis();
        TopDocs docs = searcher.search(query,10);

        System.out.println("查詢"+queryStr+"所用時間:"+(System.currentTimeMillis()-startTime));
        System.out.println("查詢到"+docs.totalHits+"條記錄");

        //加入高亮顯示的
        SimpleHTMLFormatter simpleHTMLFormatter = new SimpleHTMLFormatter("<b><font color=red>","</font></b>");
        QueryScorer scorer = new QueryScorer(query);//計算查詢結果最高的得分
        Fragmenter fragmenter = new SimpleSpanFragmenter(scorer);//根據得分算出一個片段
        Highlighter highlighter = new Highlighter(simpleHTMLFormatter,scorer);
        highlighter.setTextFragmenter(fragmenter);//設定顯示高亮的片段

        //遍歷查詢結果
        for(ScoreDoc scoreDoc : docs.scoreDocs){
            Document doc = searcher.doc(scoreDoc.doc);
            String tcontent = doc.get("tcontent");
            if(tcontent != null){
                TokenStream tokenStream =  analyzer.tokenStream("tcontent", new StringReader(tcontent));
                String summary = highlighter.getBestFragment(tokenStream, tcontent);
                System.out.println(summary);
            }
        }
        reader.close();
    }

    public static void main(String[] args){
        String indexDir = "D:\\lucene";
        String q = "內容"; //查詢這個字串
        try {
            doSearch(indexDir, q);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

查詢內容1所用時間:404
查詢到3條記錄
內容1內容啊哈哈哈
內容2內容啊哈哈哈
內容3內容啊哈哈哈

Lucene重要類解釋

IndexWriter:lucene 中最重要的的類之一,它主要是用來將文件加入索引,同時控制索引過程中的一些引數使用。

Analyzer:分析器,主要用於分析搜尋引擎遇到的各種文字。常用的有
StandardAnalyzer
分析器,StopAnalyzer 分析器,WhitespaceAnalyzer 分析器等。

Directory:索引存放的位置;lucene 提供了兩種索引存放的位置,一種是磁碟,一種是記憶體。一般情況將索引放在磁碟上;相應地lucene 提供了FSDirectory 和RAMDirectory 兩個類。

Document:文件;Document 相當於一個要進行索引的單元,任何可以想要被索引的檔案都
必須轉化為Document 物件才能進行索引。

Field:欄位。

IndexSearcher:是lucene 中最基本的檢索工具,所有的檢索都會用到IndexSearcher工具;

Query:查詢,lucene 中支援模糊查詢,語義查詢,短語查詢,組合查詢等等,如有
TermQuery,BooleanQuery,RangeQuery,WildcardQuery 等一些類。

QueryParser:是一個解析使用者輸入的工具,可以通過掃描使用者輸入的字串,生成Query物件。

Hits:在搜尋完成之後,需要把搜尋結果返回並顯示給使用者,只有這樣才算是完成搜尋的目的。在lucene 中,搜尋的結果的集合是用Hits 類的例項來表示的。

附錄

相關推薦

Apache Lucene全域性搜尋引擎入門教程

Lucene簡介 Lucent:Apache軟體基金會Jakarta專案組的一個子專案,Lucene提供了一個簡單卻強大的應用程式介面,能夠做全文索引和搜尋。在Java開發環境裡Lucene是一個成熟的免費開源工具。就其本身而言,Lucene是當前以及最

Apache Hadoop 入門教程第四章

大數據 hadoop 運行在單節點的 YARN 您可以通過設置幾個參數,另外運行 ResourceManager 的守護進程和 NodeManager 守護進程以偽分布式模式在 YARN 上運行 MapReduce job。 以下是運行步驟。 (1)配置 etc/hadoop/mapred-site.

Apache Hadoop 入門教程第二章

大數據 hadoop Apache Hadoop 單節點上的安裝配置 下面將演示快速完成在單節點上的 Hadoop 安裝與配置,以便你對 Hadoop HDFS 和 MapReduce 框架有所體會。 先決條件 支持平臺: GNU/Linux:已經證實了 Hadoop 在 GNU/Linux 平臺

Apache Hadoop 入門教程第一章

大數據 hadoop Apache Hadoop 是一個由 Apache 基金會所開發的分布式系統基礎架構。可以讓用戶在不了解分布式底層細節的情況下,開發出可靠、可擴展的分布式計算應用。 Apache Hadoop 框架,允許用戶使用簡單的編程模型來實現計算機集群的大型數據集的分布式處理。它的目的是支

Apache Hadoop 入門教程第三章

hadoop 大數據 免密碼 ssh 設置 現在確認能否不輸入口令就用 ssh 登錄 localhost: $ ssh localhost1如果不輸入口令就無法用 ssh 登陸 localhost,執行下面的命令: $ ssh-keygen -t rsa -P ‘‘ -f ~/.ssh/id_rsa$

Apache Flume 入門教程

概要 Apache Flume 是一個分散式,可靠且可用的系統,用於有效地從許多不同的源收集、聚合和移動大量日誌資料到一個集中式的資料儲存區。 Flume 的使用不只限於日誌資料。因為資料來源可以定製,flume 可以被用來傳輸大量事件資料,這些資料不僅僅包括網路通訊資料、社交媒體產生的資料、電子郵件資訊

Apache Kafka核心元件和流程-協調器(消費者和組協調器)-設計-原理(入門教程輕鬆學)

作者:稀有氣體 來源:CSDN 原文:https://blog.csdn.net/liyiming2017/article/details/82805479 版權宣告:本文為博主原創文章,轉載請附上博文連結! 本入門教程,涵蓋Kafka核心內容,通過例項和大量圖表,幫助學習

Apache Shiro 快速入門教程

第一部分 什麼是Apache Shiro 1、什麼是 apache shiro : Apache Shiro是一個功能強大且易於使用的Java安全框架,提供了認證,授權,加密,和會話管理 如同 spring security 一樣

全文搜尋引擎 Elasticsearch 入門教程-Index

前言: 之前已經說過最近正在做資料建設,爬取資料之後經過處理,最終匯入到ElasticSearch中,並編寫公共介面以提供給後臺進行檢索操作;本來想等把ElasticSearch官方API都看過一遍,形成思維導圖之後再整理出來,因為熟悉一個工具,它能做到的,比你知道它能做到的要全面也重要的多,但是整理了兩章之

Apache Kafka入門教程輕鬆學-第四章 Kafka核心元件和流程-設計-原理(二)協調器(消費者和組協調器)

本入門教程,涵蓋Kafka核心內容,通過例項和大量圖表,幫助學習者理解,任何問題歡迎留言。 目錄: 上一節介紹了kafka工作的核心元件--控制器。本節將介紹消費者密切相關的元件--協調器。它負責消費者的出入組工作。大家可以回想一下kafka核心概念中關於吃蘋果的場景,如

Apache Solr7.4 入門教程(一)

一、 Apache Solr 簡介 Apache Solr 是Apache Lucene專案的開源企業搜尋平臺。其主要功能包括全文檢索、命中標示、分面搜尋、動態聚類、資料庫整合,以及富文字(如Word、PDF)的處理。Solr是高度可擴充套件的,並提供了分散式搜尋和索引複製。Solr是最流行的企

Apache Kafka入門教程輕鬆學- Kafka核心概念

本入門教程,涵蓋Kafka核心內容,通過例項和大量圖表,幫助學習者理解,任何問題歡迎留言。 目錄: 本章是學習kafka的核心章節,涵蓋內容比較多,在理解上有一定的難度,需要反覆閱讀理解,才能參透Kafka的設計思想。 1、Kafka叢集結構 在第一章我給出過一個訊息

Apache Kafka入門教程輕鬆學-第四章 Kafka核心元件和流程-設計-原理(一)控制器

本入門教程,涵蓋Kafka核心內容,通過例項和大量圖表,幫助學習者理解,任何問題歡迎留言。 目錄: 通過前幾章的學習,我們已經從巨集觀層面瞭解了kafka的設計理念。包括kafka叢集的組成、訊息的主題、主題的分割槽、分割槽的副本等內容。接下來我們會繼續深入,瞭解kafk

Apache Solr7.4 入門教程(二)

四、建立core例項 1. core簡介 簡單說core就是solr的一個例項,一個solr服務下可以有多個core,每個core下都有自己的索引庫和與之相應的配置檔案,所以在操作solr建立索引之前要建立一個core,因為索引都存在core下面。 2. core建立 core的建立

Apache Kafka入門教程輕鬆學-第四章 Kafka核心元件和流程-設計-原理(四)副本管理器

本入門教程,涵蓋Kafka核心內容,通過例項和大量圖表,幫助學習者理解,任何問題歡迎留言。 目錄: 本章簡單介紹了副本管理器,副本管理器負責分割槽及其副本的管理。副本管理器具體的工作流程可以參考牟大恩所著的《Kafka入門與實踐》。 副本管理器 副本機制使得kafka

Apache Storm 入門教程

1、瞭解Storm 1.1、什麼是Storm? 疑問:已經有了Hadoop,為什麼還要有Storm? Storm是一個開源免費的分散式實時計算系統,Storm可以輕鬆的處理無界的資料流。 Storm有許多用例:實時分析、線上機器學習、連

Apache Lucene 7.6.0 釋出,Java 全文搜尋引擎

   Apache Lucene 7.6.0 釋出了,下載地址 >>> http://lucene.apache.org/core/downloads。 Lucene 是 Apache 軟體基金會一個開放原始碼的全文檢索引擎工具包,是一個全文檢索引擎

Apache Kafka 核心元件和流程-日誌管理器-設計-原理(入門教程輕鬆學)

本入門教程,涵蓋Kafka核心內容,通過例項和大量圖表,幫助學習者理解,任何問題歡迎留言。 目錄: 上一節介紹了協調器。協調器主要負責消費者和kafka叢集間的協調。那麼消費者消費時,如何定位訊息呢?訊息是如何儲存呢?本節將為

Lucene 6.2.1入門教程(一) 建立索引和基本搜尋索引

  簡單說兩句,Lucene現在高版本的教程很少,網上基本是4.0以下的,目前最新版是6.2.1,所以我試著來寫寫這個版本的教程。   至於那些概念什麼的,我就不多說了,大家可以參考以前的舊教程來了解Lucene的體系結構和基本原理。大致說一下Lucene就是通過建立索引這

Apache Kafka 核心元件和流程-控制器-設計-原理(入門教程輕鬆學)

本入門教程,涵蓋Kafka核心內容,通過例項和大量圖表,幫助學習者理解,任何問題歡迎留言。 目錄: 通過前幾章的學習,我們已經從巨集觀層面瞭解了kafka的設計理念。包括kafka叢集的組成、訊息的主題、主題的分割槽、分割槽的