Lucene检索数据库

原贴地址:http://www.javaeye.com/topic/963438

全文分两部分:

一: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代码    收藏代码
  1. jdbc.driverClassName = com.mysql.jdbc.Driver  
  2. jdbc.url = jdbc:mysql://192.168.0.1/dbname?autoReconnect=true&characterEncoding=utf8  
  3. jdbc.username = root  
  4. jdbc.password = password  
  5. jdbc.maxIdle = 2  
  6. jdbc.maxActive = 4  
  7. jdbc.maxWait = 5000  
  8. jdbc.validationQuery = select 0  
  9. res.index.indexPath = D/://apache-tomcat-6.0.18//webapps//test//testHome//search//res//index1  
  10. res.index.mainDirectory = D/://apache-tomcat-6.0.18//webapps//test//testHome//search//res  

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

Java代码    收藏代码
  1. package com.test.common;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.InputStream;  
  5. import java.util.HashMap;  
  6. import java.util.Map;  
  7. import java.util.Properties;  
  8.   
  9. /**   
  10.  * PropertiesUtil.java 
  11.  * @version 1.0 
  12.  * @createTime 读取配置文件信息类 
  13.  */  
  14. public class PropertiesUtil {  
  15.   
  16.     private static String defaultPropertyFilePath = "/test.properties";  
  17.       
  18.     private static Map<String,Properties> ppsMap = new HashMap<String,Properties>();  
  19.       
  20.     /** 
  21.      * 读取默认文件的配置信息,读key返回value 
  22.      * @param key 
  23.      * @return value 
  24.      */  
  25.     public static final String getPropertyValue(String key) {  
  26.         Properties pps = getPropertyFile(defaultPropertyFilePath);  
  27.         return pps == null ? null : pps.getProperty(key);  
  28.     }  
  29.       
  30.     /** 
  31.      * 传入filePath读取指定property文件,读key返回value 
  32.      * @param propertyFilePath 
  33.      * @param key 
  34.      * @return value 
  35.      */  
  36.     public static String getPropertyValue(String propertyFilePath,String key) {  
  37.         if(propertyFilePath == null) {  
  38.             propertyFilePath = defaultPropertyFilePath;  
  39.         }  
  40.         Properties pps = getPropertyFile(propertyFilePath);  
  41.         return pps == null ? null : pps.getProperty(key);  
  42.     }  
  43.       
  44.     /** 
  45.      * 根据path返回property文件,并保存到HashMap中,提高效率 
  46.      * @param propertyFilePath 
  47.      * @return 
  48.      */  
  49.     public static Properties getPropertyFile(String propertyFilePath) {  
  50.         if(propertyFilePath == null) {  
  51.             return null;  
  52.         }  
  53.         Properties pps = ppsMap.get(propertyFilePath);  
  54.         if(pps == null) {  
  55.             InputStream in = PropertiesUtil.class.getResourceAsStream(propertyFilePath);  
  56.             pps = new Properties();  
  57.             try {  
  58.                 pps.load(in);  
  59.             } catch (IOException e) {  
  60.                 e.printStackTrace();  
  61.             }  
  62.             ppsMap.put(propertyFilePath, pps);  
  63.         }  
  64.           
  65.         return pps;  
  66.     }  
  67. }  

      3) Jdbc连接数据库获取Connection工具类,不做分析,直接上代码

Java代码    收藏代码
  1. package com.test.common;  
  2.   
  3. import java.sql.Connection;  
  4. import java.sql.DriverManager;  
  5. import java.sql.ResultSet;  
  6. import java.sql.SQLException;  
  7. import java.sql.Statement;  
  8.   
  9. /**   
  10.  * JdbcUtil.java 
  11.  * @version 1.0 
  12.  * @createTime JDBC获取Connection工具类 
  13.  */  
  14. public class JdbcUtil {  
  15.       
  16.     private static Connection conn = null;  
  17.       
  18.     private static final String URL;  
  19.       
  20.     private static final String JDBC_DRIVER;  
  21.       
  22.     private static final String USER_NAME;  
  23.       
  24.     private static final String PASSWORD;  
  25.       
  26.     static {  
  27.         URL = PropertiesUtil.getPropertyValue("jdbc.url");  
  28.         JDBC_DRIVER = PropertiesUtil.getPropertyValue("jdbc.driverClassName");  
  29.         USER_NAME = PropertiesUtil.getPropertyValue("jdbc.username");  
  30.         PASSWORD = PropertiesUtil.getPropertyValue("jdbc.password");  
  31.     }  
  32.       
  33.     public static Connection getConnection() {  
  34.         try {  
  35.             Class.forName(JDBC_DRIVER);  
  36.             conn = DriverManager.getConnection(URL, USER_NAME, PASSWORD);  
  37.         } catch (ClassNotFoundException e) {  
  38.             e.printStackTrace();  
  39.         } catch (SQLException e) {  
  40.             e.printStackTrace();  
  41.         }  
  42.         return conn;  
  43.     }  
  44.       
  45. }  

     4) 万事具备,只欠东风了,下面是核心部分,方法都有注释,不多说了,一步步来,我想肯定是没有问题的。代码如下:

Java代码    收藏代码
  1. package com.test.lucene.logic;  
  2.   
  3. import java.io.File;  
  4. import java.sql.Connection;  
  5. import java.sql.ResultSet;  
  6. import java.sql.Statement;  
  7. import java.util.ArrayList;  
  8. import java.util.List;  
  9.   
  10. import org.apache.lucene.analysis.Analyzer;  
  11. import org.apache.lucene.document.Document;  
  12. import org.apache.lucene.document.Field;  
  13. import org.apache.lucene.document.Field.TermVector;  
  14. import org.apache.lucene.index.IndexWriter;  
  15. import org.apache.lucene.queryParser.QueryParser;  
  16. import org.apache.lucene.search.IndexSearcher;  
  17. import org.apache.lucene.search.Query;  
  18. import org.apache.lucene.search.ScoreDoc;  
  19. import org.apache.lucene.search.Searcher;  
  20. import org.apache.lucene.search.TopDocs;  
  21. import org.apache.lucene.store.Directory;  
  22. import org.apache.lucene.store.FSDirectory;  
  23. import org.apache.lucene.util.Version;  
  24. import org.wltea.analyzer.lucene.IKAnalyzer;  
  25. import org.wltea.analyzer.lucene.IKSimilarity;  
  26.   
  27. import com.test.common.JdbcUtil;  
  28. import com.test.common.PropertiesUtil;  
  29. import com.test.lucene.model.SearchBean;  
  30.   
  31. /**   
  32.  * SearchLogic.java 
  33.  * @version 1.0 
  34.  * @createTime Lucene数据库检索 
  35.  */  
  36. public class SearchLogic {  
  37.   
  38.     private static Connection conn = null;  
  39.       
  40.     private static Statement stmt = null;  
  41.       
  42.     private static  ResultSet rs = null;  
  43.       
  44.     private String searchDir = PropertiesUtil.getPropertyValue("res.index.indexPath");  
  45.       
  46.     private static File indexFile = null;  
  47.       
  48.     private static Searcher searcher = null;  
  49.       
  50.     private static Analyzer analyzer = null;  
  51.       
  52.     /** 索引页面缓冲 */  
  53.     private int maxBufferedDocs = 500;  
  54.     /** 
  55.      * 获取数据库数据 
  56.      * @return ResultSet 
  57.      * @throws Exception 
  58.      */  
  59.     public List<SearchBean> getResult(String queryStr) throws Exception {  
  60.           
  61.         List<SearchBean> result = null;  
  62.         conn = JdbcUtil.getConnection();  
  63.         if(conn == null) {  
  64.             throw new Exception("数据库连接失败!");  
  65.         }  
  66.         String sql = "select articleid,title_en,title_cn,abstract_en,abstract_cn from p2p_jour_article";  
  67.         try {  
  68.             stmt = conn.createStatement();  
  69.             rs = stmt.executeQuery(sql);  
  70.             this.createIndex(rs);   //给数据库创建索引,此处执行一次,不要每次运行都创建索引,以后数据有更新可以后台调用更新索引  
  71.             TopDocs topDocs = this.search(queryStr);  
  72.   
  73.             ScoreDoc[] scoreDocs = topDocs.scoreDocs;  
  74.               
  75.             result = this.addHits2List(scoreDocs);  
  76.         } catch(Exception e) {  
  77.             e.printStackTrace();  
  78.             throw new Exception("数据库查询sql出错! sql : " + sql);  
  79.         } finally {  
  80.             if(rs != null) rs.close();  
  81.             if(stmt != null) stmt.close();  
  82.             if(conn != null) conn.close();  
  83.         }  
  84.           
  85.         return result;  
  86.     }  
  87.       
  88.     /** 
  89.      * 为数据库检索数据创建索引 
  90.      * @param rs 
  91.      * @throws Exception 
  92.      */  
  93.     private void createIndex(ResultSet rs) throws Exception {  
  94.           
  95.         Directory directory = null;  
  96.         IndexWriter indexWriter = null;  
  97.           
  98.         try {  
  99.             indexFile = new File(searchDir);  
  100.             if(!indexFile.exists()) {  
  101.                 indexFile.mkdir();  
  102.             }  
  103.             directory = FSDirectory.open(indexFile);  
  104.             analyzer = new IKAnalyzer();  
  105.               
  106.             indexWriter = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.UNLIMITED);  
  107.             indexWriter.setMaxBufferedDocs(maxBufferedDocs);  
  108.             Document doc = null;  
  109.             while(rs.next()) {  
  110.                 doc = new Document();  
  111.                 Field articleid = new Field("articleid", String.valueOf(rs  
  112.                         .getInt("articleid")), Field.Store.YES,  
  113.                         Field.Index.NOT_ANALYZED, TermVector.NO);  
  114.                 Field abstract_cn = new Field("abstract_cn", rs  
  115.                         .getString("abstract_cn") == null ? "" : rs  
  116.                         .getString("abstract_cn"), Field.Store.YES,  
  117.                         Field.Index.ANALYZED, TermVector.NO);  
  118.                 doc.add(articleid);  
  119.                 doc.add(abstract_cn);  
  120.                 indexWriter.addDocument(doc);  
  121.             }  
  122.               
  123.             indexWriter.optimize();  
  124.             indexWriter.close();  
  125.         } catch(Exception e) {  
  126.             e.printStackTrace();  
  127.         }   
  128.     }  
  129.       
  130.     /** 
  131.      * 搜索索引 
  132.      * @param queryStr 
  133.      * @return 
  134.      * @throws Exception 
  135.      */  
  136.     private TopDocs search(String queryStr) throws Exception {  
  137.   
  138.         if(searcher == null) {  
  139.             indexFile = new File(searchDir);  
  140.             searcher = new IndexSearcher(FSDirectory.open(indexFile));    
  141.         }  
  142.         searcher.setSimilarity(new IKSimilarity());  
  143.         QueryParser parser = new QueryParser(Version.LUCENE_30,"abstract_cn",new IKAnalyzer());  
  144.         Query query = parser.parse(queryStr);  
  145.   
  146.         TopDocs topDocs = searcher.search(query, searcher.maxDoc());  
  147.           
  148.         return topDocs;  
  149.     }  
  150.       
  151.     /** 
  152.      * 返回结果并添加到List中 
  153.      * @param scoreDocs 
  154.      * @return 
  155.      * @throws Exception 
  156.      */  
  157.     private List<SearchBean> addHits2List(ScoreDoc[] scoreDocs ) throws Exception {  
  158.           
  159.         List<SearchBean> listBean = new ArrayList<SearchBean>();  
  160.         SearchBean bean = null;  
  161.         for(int i=0 ; i<scoreDocs.length; i++) {  
  162.             int docId = scoreDocs[i].doc;  
  163.             Document doc = searcher.doc(docId);  
  164.             bean = new SearchBean();  
  165.             bean.setArticleid(doc.get("articleid"));  
  166.             bean.setAbstract_cn(doc.get("abstract_cn"));  
  167.             listBean.add(bean);  
  168.         }  
  169.         return listBean;  
  170.     }  
  171.       
  172.     public static void main(String[] args) {  
  173.         SearchLogic logic = new SearchLogic();  
  174.         try {  
  175.             Long startTime = System.currentTimeMillis();  
  176.             List<SearchBean> result = logic.getResult("急性   肺   潮气量   临床试验");  
  177.             int i = 0;  
  178.             for(SearchBean bean : result) {  
  179.                 if(i == 10break;  
  180.                 System.out.println("bean.name " + bean.getClass().getName()  
  181.                         + " : bean.articleid " + bean.getArticleid()  
  182.                         + " : bean.abstract_cn " + bean.getAbstract_cn());  
  183.                 i++;  
  184.             }  
  185.             System.out.println("searchBean.result.size : " + result.size());  
  186.               
  187.             Long endTime = System.currentTimeMillis();  
  188.             System.out.println("查询所花费的时间为:" + (endTime-startTime)/1000);  
  189.         } catch (Exception e) {  
  190.             e.printStackTrace();  
  191.             System.out.println(e.getMessage());  
  192.         }  
  193.     }  
  194. }  

     5) 第四步用到了一个SearchBean,其实这就是一个javabean文件,包含两个String类型(articleid和abstract_cn)的set、get方法,自己回去补上吧。

        顺便说下数据库表结构:

            tablename随便取,但要跟上面查询中的表对应

            表字段:articleid  int 类型

                        abstract_cn   varchar类型

      对表字段没有太严格的定义,本来就是用来测试的。

     6) 最后给大家提供所使用到的jar包列表:

         IKAnalyzer3.2.5Stable.jar(一位好心人建议我升级一下jar包,呵呵,最新的jar包名为:IKAnalyzer3.2.8.jar ,谢谢了!)

         lucene-analyzers-3.0.2

         lucene-core-3.0.2

         lucene-highlighter-3.0.2

         lucene-memory-3.0.2

         lucene-queries-3.0.2

         mysql-connector-java-5.0.8-bin

   好了,有兴趣的人可以试试吧,代码都经过我测试过了,虽然有些地方代码结构不是特别完整,但只是入门用而已。先有了一个成功能够运行的例子之后才有更多的心情去接着学下去,~_~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值