Lucene 02 - Lucene的入門程序(Java API的簡單使用)


1 准備環境

JDK: 1.8.0_162

IDE: Eclipse Neon.3

數據庫: MySQL 5.7.20

Lucene: 4.10.4(已經很穩定了,高版本對部分分詞器支持不好)

2 准備數據

SET FOREIGN_KEY_CHECKS=0;

-------------------------------- 
Table structure for `book`
--------------------------------
DROP TABLE IF EXISTS `book`;
CREATE TABLE `book` (  
   `id` int(11) DEFAULT NULL,  
   `bookname` varchar(500) DEFAULT NULL,  
   `price` float DEFAULT NULL,  
   `pic` varchar(200) DEFAULT NULL,  
   `bookdesc` varchar(2000) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-------------------------------- 
Records of book
--------------------------------
INSERT INTO `book` VALUES ('1', 'java從入門到精通', '56', '1.jpg', '《Java從入門到精通》是人民郵電出版社於 2010年出版的圖書, 由國家863中部軟件孵化器主編. 以零基礎講解為宗旨, 深入淺出地講解Java的各項技術及實戰技能. 本書從初學者角度出發, 通過通俗易懂的語言、豐富多彩的實例, 詳細介紹了使用Java語言進行程序開發應該掌握的各方面技術.');
INSERT INTO `book` VALUES ('2', 'java web開發', '80', '2.jpg', 'Java Web, 是用Java技術來解決相關web互聯網領域的技術總和. web包括: web服務器和web客戶端兩部分. Java在客戶端的應用有java applet, 不過使用得很少, Java在服務器端的應用非常的豐富, 比如Servlet, JSP和第三方框架等等. Java技術對Web領域的發展注入了強大的動力. ');
INSERT INTO `book` VALUES ('3', 'lucene從入門到精通', '100', '3.jpg', '本書總結搜索引擎相關理論與實際解決方案, 並給出了 Java 實現, 其中利用了流行的開源項目Lucene和Solr, 而且還包括原創的實現. 本書主要包括總體介紹部分、爬蟲部分、自然語言處理部分、全文檢索部分以及相關案例分析. 爬蟲部分介紹了網頁遍歷方法和如何實現增量抓取, 並介紹了從網頁等各種格式的文檔中提取主要內容的方法.');
INSERT INTO `book` VALUES ('4', 'lucene in action', '90', '4.jpg', '本書深入淺出地介紹了lucene——一個開源的使用java語言編寫的全文搜索引擎開發包. 它通過淺顯的語言、大量的圖注、豐富的代碼示例, 以及清晰的結構為讀者呈現出作為優秀開源項目的lucene所體現的強大功能. ');
INSERT INTO `book` VALUES ('5', 'Lucene Java精華版', '80', '5.jpg', '本書總結搜索引擎相關理論與實際解決方案, 並給出了 Java 實現, 其中利用了流行的開源項目Lucene和Solr, 而且還包括原創的實現. 本書主要包括總體介紹部分、爬蟲部分、自然語言處理部分、全文檢索部分以及相關案例分析. 爬蟲部分介紹了網頁遍歷方法和如何實現增量抓取, 並介紹了從網頁等各種格式的文檔中提取主要內容的方法. ');

3 創建工程

3.1 創建Maven Project(打包方式選jar即可)

3.2 配置pom.xml, 導入依賴

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  
  <groupId>com.healchow</groupId>
  <artifactId>lucene-first</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>lucene-first</name>
  <url>http://maven.apache.org</url>

  <properties>
       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
       <!-- mysql版本 -->
       <mysql.version>5.1.44</mysql.version>
       <!-- lucene版本 -->
       <lucene.version>4.10.4</lucene.version>
  </properties>
 
  <dependencies>
       <!-- mysql數據庫依賴 -->
       <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
       </dependency>
       <!-- lucene依賴包 -->
       <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-queryparser</artifactId>
            <version>${lucene.version}</version>
       </dependency>
       <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
       </dependency>
  </dependencies>
</project> 

4 編寫基礎代碼

4.1 編寫圖書POJO

public class Book {
    private Integer id;       // int(11) DEFAULT NULL,
    private String bookname;  // varchar(500) DEFAULT NULL,
    private Float price;      // float DEFAULT NULL,
    private String pic;       // varchar(200) DEFAULT NULL,
    private String bookdesc;  // varchar(2000) DEFAULT NULL
    
    // Getters/Setters
    
    @Override
    public String toString() {
        return "Book [id=" + id + ", bookname=" + bookname + 
            ", price=" + price + ", pic=" + pic + 
            ", bookdesc=" + bookdesc + "]";
    }
}

4.2 編寫圖書DAO接口

public interface BookDao {
    /**
     * 查詢全部圖書 
     */
    List<Book> queryBookList();
}

4.3 實現圖書DAO接口

public class BookDaoImpl implements BookDao {
    /**
     * 查詢全部圖書
     */
    public List<Book> listAll() {
        // 創建圖書結果集合List
        List<Book> books = new ArrayList<Book>();
        
        Connection conn = null;
        PreparedStatement preStatement = null;
        ResultSet resultSet = null;
        
        try {
            // 加載驅動
            Class.forName("com.mysql.jdbc.Driver");
            // 創建數據庫連接對象
            conn = DriverManager.getConnection(
                       "jdbc:mysql://127.0.0.1:3306/lucene?useSSL=true", 
                       "root", 
                       "password");
            
            // 定義查詢SQL
            String sql = "select * from book";
            // 創建Statement語句對象
            preStatement = conn.prepareStatement(sql);
            // 執行語句, 得到結果集
            resultSet = preStatement.executeQuery();
            
            // 處理結果集
            while (resultSet.next()) {
                 // 創建圖書對象
                 Book book = new Book();
                 book.setId(resultSet.getInt("id"));
                 book.setBookname(resultSet.getString("bookname"));
                 book.setPrice(resultSet.getFloat("price"));
                 book.setPic(resultSet.getString("pic"));
                 book.setBookdesc(resultSet.getString("bookdesc"));
                 // 將查詢到的結果添加到list中
                 books.add(book);
            }
       } catch (Exception e) {
            e.printStackTrace();
       } finally {
            // 釋放資源
            try {
                 if (null != conn) conn.close();
                 if (null != preStatement) preStatement.close();
                 if (null != resultSet) resultSet.close();
            } catch (Exception e) {
                 e.printStackTrace();
            }
        }
        return books;
    }
    
    /**
     * 測試功能的主方法
     */
    public static void main(String[] args) {
        // 創建圖書Dao的實現對象
        BookDao bookDao = new BookDaoImpl();
        List<Book> books = bookDao.listAll();
        
        // 如果結果不為空, 則便利輸出
        for (Book book : books) {
            System.out.println(book);
        }
    }
}

測試結果如下:

5 索引流程的實現

(1) 采集原始數據;
(2) 創建文檔對象(Document);
(3) 創建分析器對象(Analyzer), 用於分詞;
(4) 創建索引配置對象(IndexWriterConfig), 用於配置Lucene;
(5) 創建索引庫目錄位置對象(Directory), 指定索引庫的存儲位置;
(6) 創建索引寫入對象(IndexWriter), 將文檔對象寫入索引庫;
(7) 使用IndexWriter對象, 創建索引;
(8) 釋放資源.

5.1 示例代碼

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.Store;
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;

public class IndexManager {
    /**
     * 創建索引功能的測試
     * @throws Exception
     */
    @Test
    public void createIndex() throws IOException{
        // 1. 采集數據
        BookDao bookDao = new BookDaoImpl();
        List<Book> books = bookDao.listAll();
        
        // 2. 創建文檔對象
        List<Document> documents = new ArrayList<Document>();
        for (Book book : books) {
            Document document = new Document();
            // 給文檔對象添加域
            // add方法: 把域添加到文檔對象中, field參數: 要添加的域
            // TextField: 文本域, 屬性name:域的名稱, value:域的值, store:指定是否將域值保存到文檔中
            document.add(new TextField("bookId", book.getId() + "", Store.YES));
            document.add(new TextField("bookName", book.getBookname(), Store.YES));
            document.add(new TextField("bookPrice", book.getPrice() + "", Store.YES));
            document.add(new TextField("bookPic", book.getPic(), Store.YES));
            document.add(new TextField("bookDesc", book.getBookdesc(), Store.YES));

            // 將文檔對象添加到文檔對象集合中
            documents.add(document);
        }
        // 3. 創建分析器對象(Analyzer), 用於分詞
        Analyzer analyzer = new StandardAnalyzer();
        // 4. 創建索引配置對象(IndexWriterConfig), 用於配置Lucene
        // 參數一:當前使用的Lucene版本, 參數二:分析器
        IndexWriterConfig indexConfig = new IndexWriterConfig(Version.LUCENE_4_10_2, analyzer);
        // 5. 創建索引庫目錄位置對象(Directory), 指定索引庫的存儲位置
        File path = new File("/your_path/index");
        Directory directory = FSDirectory.open(path);
        // 6. 創建索引寫入對象(IndexWriter), 將文檔對象寫入索引
        IndexWriter indexWriter = new IndexWriter(directory, indexConfig);
        // 7. 使用IndexWriter對象創建索引
        for (Document doc : documents) {
            // addDocement(doc): 將文檔對象寫入索引庫
            indexWriter.addDocument(doc);
        }
        // 8. 釋放資源
        indexWriter.close();
    }
}

5.2 測試結果

說明: 只要看到以下文件, 說明索引已經創建成功了:

6 使用Luke工具查看索引

6.1 使用說明

Windows OS下,雙擊運行start.bat文件(前提是需要配置jdk的環境變量);

Mac OS下, 在終端中進入當前目錄, 然后鍵入 ./start.sh 即可運行.

6.2 運行界面一

6.3 運行界面二

6.4 運行界面三

7 檢索流程的實現

(1) 創建分析器對象(Analyzer), 用於分詞;
(2) 創建查詢對象(Query);
(3) 創建索引庫目錄位置對象(Directory), 指定索引庫的位置;
(4) 創建索引讀取對象(IndexReader), 用於讀取索引;
(5) 創建索引搜索對象(IndexSearcher), 用於執行搜索;
(6) 使用IndexSearcher對象, 執行搜索, 返回搜索結果集TopDocs;
(7) 處理結果集;
(8) 釋放資源.

7.1 使用Luke工具搜索

bookName:lucene —— 表示搜索bookName域中包含有lucene.

7.2 示例代碼

/**
 * 檢索索引功能的測試
 * @throws Exception 
 */
@Test
public void searchIndexTest() throws Exception {
    // 1. 創建分析器對象(Analyzer), 用於分詞
    Analyzer analyzer = new StandardAnalyzer();
    
    // 2. 創建查詢對象(Query)
    // 2.1 創建查詢解析器對象
    // 參數一:默認的搜索域, 參數二:使用的分析器
    QueryParser queryParser = new QueryParser("bookName", analyzer);
    // 2.2 使用查詢解析器對象, 實例化Query對象
    Query query = queryParser.parse("bookName:lucene");
    
    // 3. 創建索引庫目錄位置對象(Directory), 指定索引庫位置
    Directory directory = FSDirectory.open(new File("/your_path/index"));
    
    // 4. 創建索引讀取對象(IndexReader), 用於讀取索引
    IndexReader indexReader = DirectoryReader.open(directory);
    
    // 5. 創建索引搜索對象(IndexSearcher), 用於執行索引
    IndexSearcher searcher = new IndexSearcher(indexReader);
    
    // 6. 使用IndexSearcher對象執行搜索, 返回搜索結果集TopDocs
    // 參數一:使用的查詢對象, 參數二:指定要返回的搜索結果排序后的前n個
    TopDocs topDocs = searcher.search(query, 10);
    
    // 7. 處理結果集
    // 7.1 打印實際查詢到的結果數量
    System.out.println("實際查詢到的結果數量: " + topDocs.totalHits);
    // 7.2 獲取搜索的結果數組
    // ScoreDoc中有文檔的id及其評分
    ScoreDoc[] scoreDocs = topDocs.scoreDocs;
    for (ScoreDoc scoreDoc : scoreDocs) {
        System.out.println("= = = = = = = = = = = = = = = = = = =");
        // 獲取文檔的id和評分
        int docId = scoreDoc.doc;
        float score = scoreDoc.score;
        System.out.println("文檔id= " + docId + " , 評分= " + score);
        // 根據文檔Id, 查詢文檔數據 -- 相當於關系數據庫中根據主鍵Id查詢數據
        Document doc = searcher.doc(docId);
        System.out.println("圖書Id: " + doc.get("bookId"));
        System.out.println("圖書名稱: " + doc.get("bookName"));
        System.out.println("圖書價格: " + doc.get("bookPrice"));
        System.out.println("圖書圖片: " + doc.get("bookPic"));
        System.out.println("圖書描述: " + doc.get("bookDesc"));
    }
    
    // 8. 關閉資源
    indexReader.close();
}

7.3 測試結果

7.4 結果說明

(1) 索引庫中包含索引域和文檔域;
(2) 索引域保存索引數據(倒排索引), 用於索引;
(3) 文檔域中保存文檔數據, 用於搜索獲取數據.

7.5 IndexSearcher方法

方法 說明
indexSearcher.search(query, n) 根據Query搜索, 返回評分最高的n條記錄
indexSearcher.search(query,filter,n) 根據Query搜索, 添加過濾策略, 返回評分最高的n條記錄
indexSearcher.search(query, n, sort) 根據Query搜索, 添加排序策略, 返回評分最高的n條記錄
indexSearcher.search(booleanQuery, filter, n, sort) 根據Query搜索, 添加過濾策略, 添加排序策略, 返回評分最高的n條記錄

版權聲明

作者: 馬瘦風

出處: 博客園 馬瘦風的博客

您的支持是對博主的極大鼓勵, 感謝您的閱讀.

本文版權歸博主所有, 歡迎轉載, 但請保留此段聲明, 並在文章頁面明顯位置給出原文鏈接, 否則博主保留追究相關人員法律責任的權利.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM