1. 程式人生 > >Lucene基礎(四)-- 結合資料庫使用

Lucene基礎(四)-- 結合資料庫使用

需求

很多時候我們在用資料庫的需要使用模糊查詢,我們一般會使用like語句來做,然而這樣的做的效率不是很多(很抱歉我們親自去測,很多都這麼說的),那麼使用Lucene來檢索的話,效率會高很多。

lucene結合資料庫步驟

  1. 寫一段傳統的JDBC程式,將每條的使用者資訊從資料庫讀取出來
  2. 針對每條使用者記錄,建立一個lucene document
    Document doc = new Document();
    並根據你的需要,將使用者資訊的各個欄位對應luncene document中的field 進行新增,如:
    doc.add(new Field(“NAME”,”USERNAME”,Field.Store.YES,Field.Index.UN_TOKENIZED));
    然後將該條doc加入到索引中, 如: luceneWriter.addDocument(doc);
    這樣就建立了lucene的索引庫
  3. 編寫對索引庫的搜尋程式(看lucene文件),通過對lucene的索引庫的查詢,你可以快速找到對應記錄的ID
  4. 通過ID到資料庫中查詢相關記錄

注意
在索引的過程中,可以使用增量的方式建立索引,這樣對已經索引的記錄不在建立索引。實現思路:儲存上次(lasttime)的新增時候的id,在建立索引的時候,值查詢這個id之後的記錄進行索引,更新這個記錄下來的id,在資料庫資料修改時候,針對這個資料製作索引的修改

操作例項

package lucene_demo05;

import java.io.IOException;
import java.sql.Connection;
import
java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.TextField; import org.apache.lucene.index.CorruptIndexException; import
org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.index.IndexWriterConfig.OpenMode; 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.highlight.InvalidTokenOffsetsException; import org.apache.lucene.store.Directory; import org.apache.lucene.store.RAMDirectory; import org.apache.lucene.util.Version; import org.wltea.analyzer.lucene.IKAnalyzer; /** * * Lucene與資料庫結合使用 * * @author YipFun */ public class LuceneDemo05 { private static final String driverClassName="com.mysql.jdbc.Driver"; private static final String url="jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8"; private static final String username="****"; private static final String password="****"; private static final Version version = Version.LUCENE_4_9; private Directory directory = null; private DirectoryReader ireader = null; private IndexWriter iwriter = null; private IKAnalyzer analyzer; private Connection conn; public LuceneDemo05() { directory = new RAMDirectory(); } public IndexSearcher getSearcher(){ try { if(ireader==null) { ireader = DirectoryReader.open(directory); } else { DirectoryReader tr = DirectoryReader.openIfChanged(ireader) ; if(tr!=null) { ireader.close(); ireader = tr; } } return new IndexSearcher(ireader); } catch (CorruptIndexException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } public Connection getConnection(){ if(this.conn == null){ try { Class.forName(driverClassName); conn = DriverManager.getConnection(url, username, password); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } return conn; } private IKAnalyzer getAnalyzer(){ if(analyzer == null){ return new IKAnalyzer(); }else{ return analyzer; } } public void createIndex(){ Connection conn = getConnection(); ResultSet rs = null; PreparedStatement pstmt = null; if(conn == null){ System.out.println("get the connection error..."); return ; } String sql = "select * from t_user"; try { pstmt = conn.prepareStatement(sql); rs = pstmt.executeQuery(); IndexWriterConfig iwConfig = new IndexWriterConfig(version, getAnalyzer()); iwConfig.setOpenMode(OpenMode.CREATE_OR_APPEND); iwriter = new IndexWriter(directory,iwConfig); while(rs.next()){ int id = rs.getInt(1); String name = rs.getString(2); String psd = rs.getString(3); Document doc = new Document(); doc.add(new TextField("id", id+"",Field.Store.YES)); doc.add(new TextField("name", name+"",Field.Store.YES)); doc.add(new TextField("psd", psd+"",Field.Store.YES)); iwriter.addDocument(doc); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ try { if(iwriter != null) iwriter.close(); rs.close(); pstmt.close(); if(!conn.isClosed()){ conn.close(); } } catch (IOException e) { e.printStackTrace(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public void searchByTerm(String field,String keyword,int num) throws InvalidTokenOffsetsException{ IndexSearcher isearcher = getSearcher(); Analyzer analyzer = getAnalyzer(); //使用QueryParser查詢分析器構造Query物件 QueryParser qp = new QueryParser(version, field,analyzer); //這句所起效果? qp.setDefaultOperator(QueryParser.OR_OPERATOR); try { Query query = qp.parse(keyword); ScoreDoc[] hits; //注意searcher的幾個方法 hits = isearcher.search(query, null, num).scoreDocs; System.out.println("the ids is ="); for (int i = 0; i < hits.length; i++) { Document doc = isearcher.doc(hits[i].doc); System.out.print(doc.get("id")+" "); } } catch (IOException e) { e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); } } public static void main(String[] args) throws InvalidTokenOffsetsException { LuceneDemo05 ld = new LuceneDemo05(); ld.createIndex(); ld.searchByTerm("name", "Bruce", 100); } }

索引之後就可以拿到需要id,這個時候按id查詢資料庫的記錄,就快多了。

思考

  • 這是對單表的資料進行索引,當我們的業務複雜的是,需要的資料通常是多個表聯合查詢的結果,我們的索引是如何建立?

    1. 使用檢視,對多表建立檢視,在檢視上面建立索引?
    2. 還是單表索引,只是把聯合查詢化解,在lucene的索引中使用多次查詢,找到目標,在資料庫查詢?
  • 和資料使用的時候 ,索引到底是和資料庫資料相關聯的,還是和結果集相關聯的?

寫測試程式發現,應該是索引在資料結果集上面的。

測試如下:
t_user 表
這裡寫圖片描述
t_user_teacher 表
這裡寫圖片描述
t_teacher 表
這裡寫圖片描述

package lucene_demo05;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
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.highlight.InvalidTokenOffsetsException;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;



/**
 *
 * Lucene與資料庫結合使用
 *
 * @author YipFun
 */
public class LuceneDemo06 {

    private static final String driverClassName="com.mysql.jdbc.Driver";
    private static final String url="jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8";
    private static final String username="****";
    private static final String password="****";

    private static final Version version = Version.LUCENE_4_9;
    private Directory directory = null;
    private DirectoryReader ireader = null;
    private IndexWriter iwriter = null;
    private IKAnalyzer analyzer;

    private Connection conn;

    public LuceneDemo06() {
        directory = new RAMDirectory();
    }

    public IndexSearcher getSearcher(){
        try {
            if(ireader==null) {
                ireader = DirectoryReader.open(directory);
            } else {
                DirectoryReader tr = DirectoryReader.openIfChanged(ireader) ;
                if(tr!=null) {
                    ireader.close();
                    ireader = tr;
                }
            }
            return new IndexSearcher(ireader);
        } catch (CorruptIndexException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public Connection getConnection(){
        if(this.conn == null){
            try {
                Class.forName(driverClassName);
                conn = DriverManager.getConnection(url, username, password);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            }

        }

        return conn;
    }

    private IKAnalyzer getAnalyzer(){
        if(analyzer == null){
            return new IKAnalyzer();
        }else{
            return analyzer;
        }
    }

    public void createIndex(){
        Connection conn = getConnection();
        ResultSet rs = null;
        PreparedStatement pstmt = null;
        if(conn == null){
            System.out.println("get the connection error...");
            return ;
        }
        String sql = "select "+
                        "u.id as uid,"+
                        "u.name as uname,"+
                        "u.psd as upsd,"+
                        "u.email as uemail,"+
                        "u.tel as utel,"+
                        "t.id as tid,"+
                        "t.name as tname "+
                        "from t_user u , t_user_teacher ut ,t_teacher t "+ 
                        "where u.id=ut.u_id and ut.t_id= t.id ";
        try {
            pstmt = conn.prepareStatement(sql);
            rs = pstmt.executeQuery();

            IndexWriterConfig iwConfig =  new IndexWriterConfig(version, getAnalyzer());
            iwConfig.setOpenMode(OpenMode.CREATE_OR_APPEND);
            iwriter = new IndexWriter(directory,iwConfig);

            while(rs.next()){
                int id = rs.getInt("uid");
                String name = rs.getString("uname");
                String psd = rs.getString("upsd");
                int tid = rs.getInt("tid");
                String tname = rs.getString("tname");
                Document doc = new Document();
                doc.add(new TextField("uid", id+"",Field.Store.YES));
                doc.add(new TextField("uname", name+"",Field.Store.YES));
                doc.add(new TextField("upsd", psd+"",Field.Store.YES));
                doc.add(new TextField("tid", tid+"",Field.Store.YES));
                doc.add(new TextField("tname", tname+"",Field.Store.YES));
                iwriter.addDocument(doc);
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            try {
                if(iwriter != null)
                iwriter.close();
                rs.close();
                pstmt.close();
                if(!conn.isClosed()){
                    conn.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public void searchByTerm(String field,String keyword,int num) throws InvalidTokenOffsetsException{
         IndexSearcher isearcher = getSearcher();
         Analyzer analyzer =  getAnalyzer();
        //使用QueryParser查詢分析器構造Query物件
        QueryParser qp = new QueryParser(version,
                field,analyzer);
        //這句所起效果?
        qp.setDefaultOperator(QueryParser.OR_OPERATOR);
        try {
            Query query = qp.parse(keyword);
            ScoreDoc[] hits;

            //注意searcher的幾個方法
            hits = isearcher.search(query, null, num).scoreDocs;

            System.out.println("the ids is =");
            for (int i = 0; i < hits.length; i++) {
                Document doc = isearcher.doc(hits[i].doc);
                System.out.print(doc.get("uid")+" ");
            }

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InvalidTokenOffsetsException {
        LuceneDemo06 ld = new LuceneDemo06();
        ld.createIndex();
        ld.searchByTerm("tname", "aaa", 100);
    }
}

搜尋教師為aaa的學生的Id
結果:

載入擴充套件詞典:ext.dic
載入擴充套件停止詞典:stopword.dic
the ids is =
1 2 

總結 : 所以使用索引多表的時候直接索引結果集或者檢視是可以實現

相關推薦

Lucene基礎-- 結合資料庫使用

需求 很多時候我們在用資料庫的需要使用模糊查詢,我們一般會使用like語句來做,然而這樣的做的效率不是很多(很抱歉我們親自去測,很多都這麼說的),那麼使用Lucene來檢索的話,效率會高很多。 lucene結合資料庫步驟 寫一段傳統的JDBC程式,將

Java基礎java連線資料庫

Java 連線 MySQL和Java 連線 Oracle資料庫的一些基本總結: 1.Java 連線 MySQL資料庫 //整體封裝寫為一個方法(後續補上) public class MysqlDemo { //引入Jdbc驅動及資料庫地址URL final String Jd

Flask零基礎到專案實戰SQLAlchemy資料庫

文章來源—知了課堂的課件 一、SQLAlchemy簡介 flask_sqlalchemy是一套ORM框架。 ORM(Object Relationship Mapping):模型關係對映 ORM的好處:可以讓我們操作資料庫跟操作類的物件一樣。一個表可

Linux基礎

har jid work 區號 linu watch worker eof -1 一、系統監控 1.用top命令實時監測CPU、內存、硬盤狀態 效果類似Windows的任務管理器,默認每5秒刷新一下屏幕上的顯示結果。 [[email protected]/*

mysql基礎用戶權限管理和root密碼恢復

mysqlmysql用戶由用戶和主機名組成,[email protected]/* */,mysql的用戶和權限信息存儲在mysql庫中 mysql數據庫表: user #用戶賬號、全局權限 db #庫級別權限 host #主機 tables_priv

mysql基礎之索引

name 根據 正是 而不是 方案 加速 .com mtab 技術 索引簡介: 1、普通索引   普通索引(由關鍵字KEY或INDEX定義的索引)的唯一任務是加快對數據的訪問速度。因此,應該只為那些最經常出現在查詢條件 (WHEREcolumn=)或排序條件

JS基礎運算符

訪問 數據 js基礎 必須 減法 delete 異或 函數 按位與 一.比較運算符   1.== : 判斷兩邊值是否相等   2.>= : 判斷左邊的值是否大於或等於右邊的值   3.<= : 判斷左邊邊的值是否小於或等於右邊的值   4.> : 判斷

SQL基礎:SQL命令

版本 數據庫應用 ges odi 改變 sql per 測試 數據類型 1、CREATE INDEX 語句   CREATE INDEX 語句用於在表中創建索引。在不讀取整個表的情況下,索引使數據庫應用程序可以更快地查找數據。   索引:在表中創建索引,以便更加快速高效地查

java並發基礎--- 取消與關閉

rime ole out sys 類型 interrupt 來看 方法 發出   《java並發編程實戰》的第7章是任務的取消與關閉。我覺得這一章和第6章任務執行同樣重要,一個在行為良好的軟件和勉強運行的軟件之間的最主要的區別就是,行為良好的軟件能很完善的處理失敗、關閉和取

3D數學基礎元數和歐拉角

transform 推薦 中間 應該 它的 轉變 編輯器 最簡 組件 一、四元數   四元數本質上是個高階復數,可視為復數的擴展,表達式為y=a+bi+cj+dk。在說矩陣旋轉的時候提到了它,當然四元數在Unity裏面主要作用也在於此。在Unity編輯器中的Transfor

計算機網絡基礎——數據鏈路層和網絡層協議及設備

數據鏈路層 路由器 一、數據鏈路層 位於網絡層與物理層之間1、功能 -- 數據鏈路的建立、維護與拆除 --幀包裝、幀傳輸、幀同步 --幀的差錯恢復 --流量控制 2.以太網 -- 以太網工作在數據鏈路層。我們平常使用的局域網就是以太網。 --以太網采用CSMA/C

Kotlin基礎Lambda編程

構造 引用 元素 允許 其他 create text 顯示 tag Lambda編程 一、Lambda表達式和成員引用 一)Lambda表達式語法 1 //註意與Java8中的區別 2 val sum={ x:Int,y:Int -> x+y } 3

Hadoop 框架基礎

釋放 top gem orien 系統啟動 -s blog 希望 記錄 ** Hadoop 框架基礎(四) 上一節雖然大概了解了一下 mapreduce,徒手抓了海膽,不對,徒手寫了 mapreduce 代碼,也運行了出來。但是沒有做更深入的理解和探討。 那麽…… 本節

路由交換基礎——ACL訪問控制列表

per not 由器 地址 同時 擴展 數據包 而不是 需要 一、ACL1.作用訪問控制列表(Access Control List),是路由器和交換機接口的指令列表,用來控制端口進出的數據包。ACL可以過濾網絡中的流量,是控制訪問的一種網絡技術手段。配置ACL後,可以限制

Java基礎

抽象類 使用 發生 註意 方法 類實例化 類方法 內容 大寫字母 一、方法 1、方法的定義   方法也叫函數,就是一個能獨立完成某個功能的一段代碼。方法可以看作一個整體。 語法: 修飾符 返回類型 方法名字(數據類型 變量名,數據類型 變量名,……[形式參數(0個到n

MySQL數據庫基礎——MySQL數據庫創建實例

MySQL 數據庫 基礎 MySQL數據庫基礎(四)——MySQL數據庫創建實例 一、創建數據庫 1、創建數據庫 創建數據庫,指定數據庫的默認字符集為utf8。create database schoolDB default character set utf8;連接數據庫,客戶端必須選擇UTF8

JAVA基礎面試題

Java基礎 Java程序員面試 面試題: 構造代碼塊,構造方法,靜態代碼的優先級? 靜態代碼塊>構造代碼塊>構造方法 面試題: overload和override的區別?overload:方法重載方法名一樣,參數不同,和返回值沒有關系參數不同:1)參數個數不同2)參數類型不同over

shell腳本基礎

shell一、shell中的函數 函數就是把一段代碼整理到了一個小單元中,並給這個小單元起一個名字,當用到這段代碼時直接調用這個小單元的名字即可。 1、函數格式 function f_name() { command } 函數必須要放在腳本最前面。 2、shell函數實例 實例1: [root

密碼學基礎算法的安全性

區塊鏈兄弟區塊鏈技術社區區塊鏈兄弟社區,區塊鏈技術專業問答先行者,中國區塊鏈技術愛好者聚集地作者:於中陽來源:區塊鏈兄弟原文鏈接:http://www.blockchainbrother.com/article/83著權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請註明出處。算法的安全性根據被破譯的難易

Linux基礎——訊號量與PV操作

在計算機作業系統中,PV操作是程序管理中的難點。1、基本含義      什麼是訊號量?訊號量(semaphore)的資料結構為一個值和一個指標,指標指向等待該訊號量的下一個程序。訊號量的值與相應資源的使用情況有關。當它的值大於0時,表示當前可用資源的