lucene学习

 

全文分两部分:

一:Lucene简介

      Lucene版本:3.0.2

     全文检索大体分两个部分:索引创建(Indexing)和搜索索引(Search

     1. 索引过程:

        1) 有一系列被索引文件(此处所指即数据库数据)

        2) 被索引文件经过语法分析和语言处理形成一系列词(Term)

        3) 经过索引创建形成词典和反向索引表。

        4) 通过索引存储将索引写入硬盘。

    2. 搜索过程:

       a) 用户输入查询语句。

       b) 对查询语句经过语法分析和语言分析得到一系列词(Term)

       c) 通过语法分析得到一个查询树。

       d) 通过索引存储将索引读入到内存。

       e) 利用查询树搜索索引,从而得到每个词(Term)的文档链表,对文档链表进行交,差,并得到结果文档。

       f) 将搜索到的结果文档对查询的相关性进行排序。

       g) 返回查询结果给用户。

 

 

   • 索引过程如下:

       ◦ 创建一个IndexWriter用来写索引文件,它有几个参数,INDEX_DIR就是索引文件所存放的位置,Analyzer便是用来对文档进行词法分析和语言处理的。

       ◦ 创建一个Document代表我们要索引的文档。

       ◦ 将不同的Field加入到文档中。我们知道,一篇文档有多种信息,如题目,作者,修改时间,内容等。不同类型的信息用不同的Field来表示,在本例子中,一共有两类信息进行了索引,一个是文件路径,一个是文件内容。其中FileReaderSRC_FILE就表示要索引的源文件。

       ◦ IndexWriter调用函数addDocument将索引写到索引文件夹中。

   • 搜索过程如下:

       ◦ IndexReader将磁盘上的索引信息读入到内存,INDEX_DIR就是索引文件存放的位置。

       ◦ 创建IndexSearcher准备进行搜索。

       ◦ 创建Analyer用来对查询语句进行词法分析和语言处理。

       ◦ 创建QueryParser用来对查询语句进行语法分析。

       ◦ QueryParser调用parser进行语法分析,形成查询语法树,放到Query中。

       ◦ IndexSearcher调用search对查询语法树Query进行搜索,得到结果TopScoreDocCollector

二:代码示例(本文重点部分)

      1) 首先是连接数据库的jdbc配置文件信息以及存放索引文件的路径配置信息test.properties:

 

jdbc.driverClassName = oracle.jdbc.driver.OracleDriver

jdbc.url = jdbc:oracle:thin:@10.20.151.4:1521:ptdev

jdbc.username = pt  

jdbc.password = pt  

jdbc.maxIdle = 2  

jdbc.maxActive = 4  

jdbc.maxWait = 5000  

jdbc.validationQuery = select 0  

res.index.indexPath = D\:\\webapps\\test\\testHome\\search\\res\\index1  

res.index.mainDirectory = D\:\\webapps\\test\\testHome\\search\\res  

2) 读取资源文件的工具类PropertiesUtil.java:

 

package com.lucene;

 

import java.io.IOException;

import java.io.InputStream;

import java.util.HashMap;

import java.util.Map;

import java.util.Properties;

/**   

 * PropertiesUtil.java 

 * @version 1.0 

 * @createTime 读取配置文件信息类 

 */  

public class PropertiesUtil {

private static String defaultPropertyFilePath = "test.properties";  

 

    private static Map<String,Properties> ppsMap = new HashMap<String,Properties>();  

 

    /** 

     * 读取默认文件的配置信息,读key返回value 

     * @param key 

     * @return value 

     */  

    public static final String getPropertyValue(String key) {  

        Properties pps = getPropertyFile(defaultPropertyFilePath);  

        return pps == null ? null : pps.getProperty(key);  

    }  

 

    /** 

     * 传入filePath读取指定property文件,读key返回value 

     * @param propertyFilePath 

     * @param key 

     * @return value 

     */  

    public static String getPropertyValue(String propertyFilePath,String key) {  

        if(propertyFilePath == null) {  

            propertyFilePath = defaultPropertyFilePath;  

        }  

        Properties pps = getPropertyFile(propertyFilePath);  

        return pps == null ? null : pps.getProperty(key);  

    }  

 

    /** 

     * 根据path返回property文件,并保存到HashMap中,提高效率 

     * @param propertyFilePath 

     * @return 

     */  

    public static Properties getPropertyFile(String propertyFilePath) {  

        if(propertyFilePath == null) {  

            return null;  

        }  

        Properties pps = ppsMap.get(propertyFilePath);  

        if(pps == null) {  

            InputStream in = PropertiesUtil.class.getResourceAsStream(propertyFilePath);  

            pps = new Properties();  

            try {  

                pps.load(in);  

            } catch (IOException e) {  

                e.printStackTrace();  

            }  

            ppsMap.put(propertyFilePath, pps);  

        }  

 

        return pps;  

    }  

 

    public static void main(String args[])

    {

    System.out.println(PropertiesUtil.getPropertyValue("jdbc.url"));

    }

}

  3) Jdbc连接数据库获取Connection工具类JdbcUtil.java:
package com.lucene;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**   
 * JdbcUtil.java 
 * @version 1.0 
 * @createTime JDBC获取Connection工具类 
 */  
public class JdbcUtil {
private static Connection conn = null;  
     
   private static final String URL;  
     
   private static final String JDBC_DRIVER;  
     
   private static final String USER_NAME;  
     
   private static final String PASSWORD;  
     
   static {  
       URL = PropertiesUtil.getPropertyValue("jdbc.url");  
       JDBC_DRIVER = PropertiesUtil.getPropertyValue("jdbc.driverClassName");  
       USER_NAME = PropertiesUtil.getPropertyValue("jdbc.username");  
       PASSWORD = PropertiesUtil.getPropertyValue("jdbc.password");  
   }  
     
   public static Connection getConnection() {  
       try {  
           Class.forName(JDBC_DRIVER);  
           conn = DriverManager.getConnection(URL, USER_NAME, PASSWORD);  
       } catch (ClassNotFoundException e) {  
           e.printStackTrace();  
       } catch (SQLException e) {  
           e.printStackTrace();  
       }  
       return conn;  
   }  
     
}
 4) .测试lucene,  SearchLogic.java:
package com.lucene;

import java.io.File;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.TermVector;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Searcher;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;
import org.wltea.analyzer.lucene.IKSimilarity;

/**   
 * SearchLogic.java 
 * @version 1.0 
 * @createTime Lucene数据库检索 
 */  
public class SearchLogic {
private static Connection conn = null;  
    
    private static Statement stmt = null;  
      
    private static  ResultSet rs = null;  
      
    private String searchDir = PropertiesUtil.getPropertyValue("res.index.indexPath");  
      
    private static File indexFile = null;  
      
    private static Searcher searcher = null;  
      
    private static Analyzer analyzer = null;  
      
    /** 索引页面缓冲 */  
    private int maxBufferedDocs = 500;  
    /** 
     * 获取数据库数据 
     * @return ResultSet 
     * @throws Exception 
     */  
    public List<SearchBean> getResult(String queryStr) throws Exception {  
          
        List<SearchBean> result = null;  
        conn = JdbcUtil.getConnection();  
        if(conn == null) {  
            throw new Exception("数据库连接失败!");  
        }  
        String sql = "select articleid,title_cn,abstract_cn from p2p_jour_article";  
        try {  
            stmt = conn.createStatement();  
            rs = stmt.executeQuery(sql);  
            this.createIndex(rs);   //给数据库创建索引,此处执行一次,不要每次运行都创建索引,以后数据有更新可以后台调用更新索引  
            TopDocs topDocs = this.search(queryStr);  
  
            ScoreDoc[] scoreDocs = topDocs.scoreDocs;  
              
            result = this.addHits2List(scoreDocs);  
        } catch(Exception e) {  
            e.printStackTrace();  
            throw new Exception("数据库查询sql出错! sql : " + sql);  
        } finally {  
            if(rs != null) rs.close();  
            if(stmt != null) stmt.close();  
            if(conn != null) conn.close();  
        }  
          
        return result;  
    }  
      
    /** 
     * 为数据库检索数据创建索引 
     * @param rs 
     * @throws Exception 
     */  
    private void createIndex(ResultSet rs) throws Exception {  
          
        Directory directory = null;  
        IndexWriter indexWriter = null;  
          
        try {  
            indexFile = new File(searchDir);  
            if(!indexFile.exists()) {  
                indexFile.mkdir();  
            }  
            directory = FSDirectory.open(indexFile);  
            analyzer = new IKAnalyzer();  
              
            indexWriter = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.UNLIMITED);  
            indexWriter.setMaxBufferedDocs(maxBufferedDocs);  
            Document doc = null;  
            while(rs.next()) {  
                doc = new Document();  
                Field articleid = new Field("articleid", String.valueOf(rs  
                        .getInt("articleid")), Field.Store.YES,  
                        Field.Index.NOT_ANALYZED, TermVector.NO);  
                Field abstract_cn = new Field("abstract_cn", rs  
                        .getString("abstract_cn") == null ? "" : rs  
                        .getString("abstract_cn"), Field.Store.YES,  
                        Field.Index.ANALYZED, TermVector.NO);  
                doc.add(articleid);  
                doc.add(abstract_cn);  
                indexWriter.addDocument(doc);  
            }  
              
            indexWriter.optimize();  
            indexWriter.close();  
        } catch(Exception e) {  
            e.printStackTrace();  
        }   
    }  
      
    /** 
     * 搜索索引 
     * @param queryStr 
     * @return 
     * @throws Exception 
     */  
    private TopDocs search(String queryStr) throws Exception {  
  
        if(searcher == null) {  
            indexFile = new File(searchDir);  
            searcher = new IndexSearcher(FSDirectory.open(indexFile));    
        }  
        searcher.setSimilarity(new IKSimilarity());  
        QueryParser parser = new QueryParser(Version.LUCENE_30,"abstract_cn",new IKAnalyzer());  
        Query query = parser.parse(queryStr);  
  
        TopDocs topDocs = searcher.search(query, searcher.maxDoc());  
          
        return topDocs;  
    }  
      
    /** 
     * 返回结果并添加到List中 
     * @param scoreDocs 
     * @return 
     * @throws Exception 
     */  
    private List<SearchBean> addHits2List(ScoreDoc[] scoreDocs ) throws Exception {  
          
        List<SearchBean> listBean = new ArrayList<SearchBean>();  
        SearchBean bean = null;  
        for(int i=0 ; i<scoreDocs.length; i++) {  
            int docId = scoreDocs[i].doc;  
            Document doc = searcher.doc(docId);  
            bean = new SearchBean();  
            bean.setArticleid(doc.get("articleid"));  
            bean.setAbstract_cn(doc.get("abstract_cn"));  
            listBean.add(bean);  
        }  
        return listBean;  
    }  
      
    public static void main(String[] args) {  
        SearchLogic logic = new SearchLogic();  
        try {  
            Long startTime = System.currentTimeMillis();  
            List<SearchBean> result = logic.getResult("222");  
            int i = 0;  
            for(SearchBean bean : result) {  
                if(i == 10) break;  
                System.out.println("bean.name " + bean.getClass().getName()  
                        + " : bean.articleid " + bean.getArticleid()  
                        + " : bean.abstract_cn " + bean.getAbstract_cn());  
                i++;  
            }  
            System.out.println("searchBean.result.size : " + result.size());  
              
            Long endTime = System.currentTimeMillis();  
            System.out.println("查询所花费的时间为:" + (endTime-startTime)/1000);  
        } catch (Exception e) {  
            e.printStackTrace();  
            System.out.println(e.getMessage());  
        }  
    }  
}
SearchBean.java:
package com.lucene;

public class SearchBean {
private String articleid;
private String abstract_cn;
public String getArticleid() {
return articleid;
}
public void setArticleid(String articleid) {
this.articleid = articleid;
}
public String getAbstract_cn() {
return abstract_cn;
}
public void setAbstract_cn(String abstract_cn) {
this.abstract_cn = abstract_cn;
}
}

表p2p_jour_article结构如下:
SQL> desc p2p_jour_article
Name        Type         Nullable Default Comments 
----------- ------------ -------- ------- -------- 
ARTICLEID   VARCHAR2(10) Y                         
ABSTRACT_CN VARCHAR2(20) Y                         
TITLE_CN    VARCHAR2(30) Y                         

数据如下:


 


运行SearchLogic类main方法(需引入附件中的2个jar包),结果如下:



 由此查询出了ABSTRACT_CN=‘222’的记录

 

相关代码结构如下:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值