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

时间: 2024-10-18 15:33:11

Lucene基础(四)-- 结合数据库使用的相关文章

Lucene全文检索之-Lucene基础

Lucene是全文检索引擎 一.在学习Lucene之前我们先思考下,Lucene存在的意义. 1.在之前我们的应用场景中,基于数据库的检索,我们使用like语法进行.但是基于like语法效率低下.达不到我们对应用的使用要求. 而使用Lucene对我们的数据建立索引效率高速度快,满足企业要求. 我们使用Lucene先对整个结构建立索引库,然后根据索引去查找我们需要匹配的内容,效率高速度快,方便我们快速检索信息-这也是Lucene存在的目的. 2.有些查找数据库做不了,比如我们想查找附件中内容的匹配

Laravel教程 四:数据库和Eloquent

Laravel教程 四:数据库和Eloquent 此文章为原创文章,未经同意,禁止转载. Eloquent Database 上一篇写了一些Laravel Blade的基本用法和给视图传递变量的几种方式, 这一节我们来说说跟数据库打交道的数据库配置和Laravel强大的Eloquent. Laravel的数据库配置 本部分内容为下节做准备 Laravel的配置文件都是在项目目录的config/文件夹之下,这里也就是在blog/config文件夹之下,你可以打开这个文件夹看看,你面有很多配置文件:

JS基础四

1.函数是一组可以随时随地运行的语句. 函数是 ECMAScript 的核心. 函数是由这样的方式进行声明的:关键字 function.函数名.一组参数,以及置于括号中的待执行代码. 2.闭包,指的是词法表示包括不被计算的变量的函数,也就是说,函数可以使用函数之外定义的变量. 3.把对象的所有引用都设置为 null,可以强制性地废除对象.object  设置为null, 4.本地对象(native object) Object Function Array String Boolean Numb

Java基础四

Java基础四 一.Switch语句 二.if和switch区别 推荐使用if 三.函数 Java中的函数和方法是同一个词 四.数组 4.1.数组常见错误 五.内存机制 六.转换成十六进制 移位 &操作 6.2 查表法求十六进制 查表法很多时候都非常好用,这样就非常好了,真的非常好用 算的时候直接移四位,我喜欢,我觉得以后可以多做移位运算,真的是简单方便 6.3 查表法求星期几

python学习记录第四篇--数据库

只要用到MySQLdb,使用时请先安装MySQLdb,百度上可以下载! #coding=utf-8'''@author: 使用python操作MySQL数据库'''import MySQLdb#import MySQLdb.cursorsconn=MySQLdb.connect(user='root',passwd='root') #connect共三个值,user,passwd,host,无密码且连接本地数据库时,可以都为空.cur=conn.cursor() #创建游标,使用游标进行数据库操

SCCM 2012 R2 实战系列(四)—数据库及必要组件安装

下面来介绍其余的组件,SCCM是需要数据库支持的,因此必须在SCCM服务器上首先将数据库安装好,另外SCCM部署中需要用到ADK中的部署工具,我们还需要在SCCM中安装Windows ADK 8.1,在部署过程中通过SCCM部署客户端计算机需要用到WDS组件,另外我们还需要配置IIS,这些都是提前需要准备好的,下面来介绍安装配置方法,首先是数据库的安装 这里一定要注意: SCCM不支持Express版本的数据库,数据库必须要打SP补丁,否则SCCM将无法正常识别,另外数据库如果是SQL 2012

C# Socket基础(四)之客户端向服务器发消息

private Socket socketClient;//客户端套接字,关于实例化请参考C# Socket基础(三)之客户端连接服务器和接收消息 客户端发送消息 1 /// <summary> 2 /// 发送数据到服务端 3 /// </summary> 4 private void Send() 5 { 6 if (socketClient == null) 7 { 8 9 ShowMsg("服务器未启动!"); 10 return; 11 } 12 by

Python全栈开发【基础四】

Python全栈开发[基础四] 本节内容: 匿名函数(lambda) 函数式编程(map,filter,reduce) 文件处理 匿名函数 lambda表达式:对于简单的函数,存在一种简便的表示方式,即lambda表达式 1 #这段代码 2 def calc(n): 3 return n**n 4 print(calc(10)) 5 6 #换成匿名函数 7 calc = lambda n:n**n 8 print(calc(10)) 匿名函数主要是和其它函数搭配使用 举例: 1 ########

Object Pascal 语法之语言基础(四)

1.8 过程与函数 过程与函数是实现一定功能的语句块,是程序中的特定功能单元.可以在程序的其他地方被调用,也可以进行递归调用.过程与函数的区别在于过程没有返回值,而函数有返回值. 1.过程与函数的定义过程与函数的定义包括过程原型或函数原型.过程体或函数体的定义.过程定义的形式如下: procedure ProcedureName(ParameterList); directives; var LocalDeclarations; begin statements end; ProcedureNa

将 Shiro 作为应用的权限基础 四:shiro的配置说明

Apache Shiro的配置主要分为四部分: SecurityManager的配置 URL过滤器的配置 静态用户配置 静态角色配置 其中,由于用户.角色一般由后台进行操作的动态数据,比如通过@RequiresRoles注解控制某方法的访问,因此Shiro配置一般仅包含前两项的配置. SecurityManager的配置:  [html] view plaincopy <span style="font-size:18px"><!--shiro securityMan