使用Lucene对数据库搜索

         前面介绍了Lucene对于文件怎么进行索引和搜索,这次就来说说lucene怎么对数据库进行索引和搜索。众所周知,数据库数据可以通过SQL来查询,Java EE系统中也可以通过Hbiernate,Ibatis,Spring JdbcTemplate或者直接通过JDBC API来访问,但是当数据库很大时,执行SQL语句的代价就很大,速度也会很忙,尤其是在大量用户高并发量访问的情况下尤为明显,就算是给数据库创建索引后提高也有限,而且并不是所有的数据库都支持全文检索。所以通过lucene创建数据库索引能够大大提高系统的性能,其优点主要体现在以下几个方面:

  • 通过创建唯一索引,能保证数据的唯一性;
  • 大大提高了数据检索的速度,这是创建数据库索引的重要原因;
  • 加快了表与表之间的链接,对实现数据参考完整性具有重大的意义;
  • 通过创建索引,在查询过程中采用优化策略,能够提高系统的性能;
  • 使用分组和排序字句进行数据检索时,通过创建索引能够减少查询中分组和排序的时间;
  • 可特别针对经常需要检索的列创建索引,能够减少盲目搜索的时间,大大提高搜索效率;


下面看一下对于数据库创建索引的例子,我有一个mysql数据库test,其中有一张University的表,记录了大学信息:

package com.seiya;

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.StringField;
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.wltea.analyzer.lucene.IKAnalyzer;

import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

/**
 * Created by dell on 2015/8/10.
 * 对数据库数据做索引
 */
public class DataBaseIndex {

    public static final String INDEXPATH = "D://indexFile//dbIndex";

    private static String url="jdbc:mysql://localhost:3306/test?user=root&password=root&useUnicode=true&characterEncoding=UTF-8";

    public static boolean createIndex() {
        try {
            Directory dir = FSDirectory.open(Paths.get(INDEXPATH)); // 使用了nio,存储索引的路径
            Analyzer analyzer = new StandardAnalyzer(); // 无参构造函数
            IndexWriterConfig iwc = new IndexWriterConfig(analyzer); // 新的IndexWriter配置类
            iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE); // 创建模式打开
            //iwc.setRAMBufferSizeMB(256.0); // 设置内存缓存的大小,提高索引效率,不过如果修改过大的值,需要修改JVM的内存值
            IndexWriter writer = new IndexWriter(dir, iwc); // 创建IndexWriter

            Class.forName("com.mysql.jdbc.Driver");
            Connection con = DriverManager.getConnection(url);
            Statement stmt = con.createStatement();
            String query = "select * from University";
            System.out.println("query==="+query);
            ResultSet rs=stmt.executeQuery(query);
            while(rs.next()) {
                Document doc = new Document();
                String cName = rs.getString("UniversityName");
                System.out.println("cName--------------->"+cName);
                String eName = rs.getString("E_Name");
                System.out.println("eName--------------->"+eName);
                String type = rs.getString("Type");
                String location = rs.getString("Location");
                doc.add(new TextField("cName",cName,Field.Store.YES));
                doc.add(new TextField("eName",eName,Field.Store.YES)); // 做analyze
                doc.add(new StringField("type",type,Field.Store.YES)); // 不做analyze
                doc.add(new StringField("location",location,Field.Store.YES));
                writer.addDocument(doc);
            }
            writer.close();
        }catch(Exception ex) {
            ex.printStackTrace();
        }
        return true;
    }

    public static void main(String[] args) {
        createIndex();
    }

}

这里要注意的是,对于lucene5,StringField是不做analyze的,TextField是做了分词的。

再来看一下查询数据库数据的例子:

package com.seiya;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
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.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.wltea.analyzer.lucene.IKAnalyzer;

import java.io.IOException;
import java.nio.file.Paths;


/**
 * Created by dell on 2015/8/11.
 */
public class DataBaseSearcher {

    public static final String INDEXPATH = "D://indexFile//dbIndex";
    private static int TOP_NUM = 100; // 显示记录数

    public static void searchData(String queryStr) {
        Directory dir = null;
        try {
            dir = FSDirectory.open(Paths.get(INDEXPATH));
            IndexReader reader = DirectoryReader.open(dir);
            IndexSearcher searcher = new IndexSearcher(reader);
            Analyzer analyzer = new StandardAnalyzer();
            String fieldString = "cName";
            QueryParser parser = new QueryParser(fieldString, analyzer);
            parser.setDefaultOperator(QueryParser.AND_OPERATOR);
            Query query = parser.parse(queryStr);
            TopDocs hits = searcher.search(query,5); // 查找操作
            for(ScoreDoc scoreDoc : hits.scoreDocs) {
                Document doc = searcher.doc(scoreDoc.doc); // 根据文档打分得到文档的内容
                System.out.println(doc.get("cName")); // 找到文件后,输出路径
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ParseException ex) {
            ex.printStackTrace();
        }
    }

    public static void main(String[] args) {
        searchData("大学");
    }

}

由于IKAnalyzer目前还没有支持lucene5,所以对于需要用到IK之类的中文分词器的程序,最好还是使用稳定的Lucene4,当然也可以自己修改IKAnalyzer的源代码进行适配。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值