1. 程式人生 > >Apache Lucene的一個簡單示例

Apache Lucene的一個簡單示例

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

官方網站:http://lucene.apache.org

**

一個簡單的例子

**

1、引入Maven依賴
JDK版本:1.8.0_181
Lucene版本:4.0.0
POI版本:3.17,可處理2016之後的Word和Excel
最新版本可到此查詢mvnrepository

    <properties>
        <lucene.version>4.0.0</lucene.version>
        <poi.version>3.17</poi.version>
    </properties>
<dependencies> <!--Lucene 核心包 START --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-core</artifactId> <version>${lucene.version}</version> </dependency>
<!--一般分詞器,適用於英文分詞--> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-analyzers-common</artifactId> <version>${lucene.version}</version> </dependency> <!--中文分詞器--> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-analyzers-smartcn</artifactId> <version>${lucene.version}</version> </dependency> <!--對分詞索引查詢解析--> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-queryparser</artifactId> <version>${lucene.version}</version> </dependency> <!--檢索關鍵字高亮顯示--> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-highlighter</artifactId> <version>${lucene.version}</version> </dependency> <!--Lucene 核心包 END --> <!-- Excel和Word文件處理依賴 START --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>${poi.version}</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>${poi.version}</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-scratchpad</artifactId> <version>${poi.version}</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-schemas</artifactId> <version>${poi.version}</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.8</version> </dependency> <!-- Excel和Word文件處理依賴 END --> </dependencies>

2、建立需要檢索的檔案
在資料夾D:\luceneData\下手動建立1.txt,2.docx,3.xlsx三個檔案,裡面含有“中國”兩個漢字的文字內容。

3、建立檔案目錄索引

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
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.apache.lucene.util.Version;
import org.apache.poi.POIXMLTextExtractor;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

public class CreateLuceneIndex {
    private final static Logger log = LoggerFactory.getLogger(CreateLuceneIndex.class);

    private static String content = "";// 檔案裡的內容
    private static String INDEX_DIR = "D:\\luceneIndex";// 存放索引的位置
    private static String DATA_DIR = "D:\\luceneData";// 存放檔案的位置
    private static Analyzer analyzer = null;
    private static Directory directory = null;
    private static IndexWriter indexWriter = null;

    /**
     * 建立當前檔案目錄的索引
     *
     * @param path 當前檔案目錄
     * @return 是否成功
     */
    public static boolean createIndex(String path) {
        Date date1 = new Date();
        File indexFile = new File(INDEX_DIR);
        if (!indexFile.exists()) {
            indexFile.mkdirs();
        }
        List<File> fileList = getFileList(path);
        for (File file : fileList) {
            content = "";
            // 獲取檔案字尾
            String type = file.getName().substring(file.getName().lastIndexOf(".") + 1);
            if ("txt".equalsIgnoreCase(type)) {
                content += txt2String(file);
            } else if ("doc".equalsIgnoreCase(type) || "docx".equalsIgnoreCase(type)) {
                content += doc2String(file);
            } else if ("xls".equalsIgnoreCase(type) || "xlsx".equalsIgnoreCase(type)) {
                content += xls2String(file);
            }

            System.out.println("name :" + file.getName());
            System.out.println("path :" + file.getPath());
            System.out.println("content :" + content);
            System.out.println("=======================");

            try {
                analyzer = new StandardAnalyzer(Version.LUCENE_40);// 使用中文分詞器
                directory = FSDirectory.open(new File(INDEX_DIR));

                IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_40, analyzer);
                indexWriter = new IndexWriter(directory, config);
                Document document = new Document();
                document.add(new TextField("filename", file.getName(), Field.Store.YES));
                document.add(new TextField("content", content, Field.Store.YES));
                document.add(new TextField("path", file.getPath(), Field.Store.YES));
                indexWriter.addDocument(document);// 新增文件
                indexWriter.commit();
                closeWriter();// close了才真正寫到文件中
            } catch (Exception e) {
                log.error("建立檔案目錄索引異常:" + e.getMessage(), e);
                return false;
            }
        }
        Date date2 = new Date();
        System.out.println("建立索引-----耗時:" + (date2.getTime() - date1.getTime()) + "ms");
        return true;
    }

    /**
     * 過濾目錄下的檔案
     *
     * @param dirPath 想要獲取檔案的目錄
     * @return 返回檔案list
     */
    private static List<File> getFileList(String dirPath) {
        File[] files = new File(dirPath).listFiles();
        List<File> fileList = new ArrayList<File>();
        for (File file : files) {
            if (isTxtFile(file.getName())) {
                fileList.add(file);
            }
        }
        return fileList;
    }

    /**
     * 讀取txt檔案的內容
     *
     * @param file 想要讀取的檔案物件
     * @return 返回檔案內容
     */
    private static String txt2String(File file) {
        String result = "";
        try {
            // 構造一個BufferedReader類來讀取檔案(解決中文亂碼問題)
            BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "GBK"));
            String s = null;
            // 使用readLine方法,一次讀一行
            while ((s = br.readLine()) != null) {
                result += s;
            }
            br.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 讀取doc檔案內容
     *
     * @param file 想要讀取的檔案物件
     * @return 返回檔案內容
     */
    public static String doc2String(File file) {
        String result = "";
        if (file.exists() && file.isFile()) {
            InputStream is = null;
            HWPFDocument doc = null;
            XWPFDocument docx = null;
            POIXMLTextExtractor extractor = null;
            try {
                FileInputStream fis = new FileInputStream(file);
                // 判斷word的兩種格式doc,docx
                if (file.getPath().toLowerCase().endsWith("doc")) {
                    doc = new HWPFDocument(fis);
                    // 文件文字內容
                    result = doc.getDocumentText();
                } else if (file.getPath().toLowerCase().endsWith("docx")) {
                    docx = new XWPFDocument(fis);
                    extractor = new XWPFWordExtractor(docx);
                    // 文件文字內容
                    result = extractor.getText();
                } else {
                    log.error("不是word文件:" + file.getPath());
                }
            } catch (Exception e) {
                log.error("word檔案讀取異常:" + e.getMessage(), e);
            } finally {
                try {
                    if (doc != null) {
                        doc.close();
                    }
                    if (extractor != null) {
                        extractor.close();
                    }
                    if (docx != null) {
                        docx.close();
                    }
                    if (is != null) {
                        is.close();
                    }
                } catch (Exception e) {
                    log.error("關閉IO異常:" + e.getMessage(), e);
                }
            }
        }
        return result;
    }

    /**
     * 讀取xls檔案內容
     *
     * @param file 想要讀取的檔案物件
     * @return 返回檔案內容
     */
    public static String xls2String(File file) {
        String result = "";
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            Workbook workbook = null;
            // 判斷excel的兩種格式xls,xlsx
            if (file.getPath().toLowerCase().endsWith("xlsx")) {
                workbook = new XSSFWorkbook(fis);
            } else if (file.getPath().toLowerCase().endsWith("xls")) {
                workbook = new HSSFWorkbook(fis);
            }
            // 得到sheet的總數  
            int numberOfSheets = workbook.getNumberOfSheets();
            //System.out.println("一共" + numberOfSheets + "個sheet");
            // 迴圈每一個sheet  
            for (int i = 0; i < numberOfSheets; i++) {
                //得到第i個sheet  
                Sheet sheet = workbook.getSheetAt(i);
                //System.out.println(sheet.getSheetName() + "  sheet");
                // 得到行的迭代器  
                Iterator<Row> rowIterator = sheet.iterator();
                int rowCount = 0;
                // 迴圈每一行
                while (rowIterator.hasNext()) {
                    //System.out.print("第" + (++rowCount) + "行  ");
                    // 得到一行物件  
                    Row row = rowIterator.next();
                    // 得到列物件 
                    Iterator<Cell> cellIterator = row.cellIterator();
                    int columnCount = 0;
                    // 迴圈每一列
                    while (cellIterator.hasNext()) {
                        //System.out.print("第" + (++columnCount) + "列:");
                        // 得到單元格物件
                        Cell cell = cellIterator.next