Lucene入门案例

Lucene介绍

Lucene是什么?

  • Lucene是Apache软件基金会下的一个子项目。是一个成熟、免费、开放源代码的全文检索引擎工具包。提供了一套简单易用的API,方便在目标系统中实现全文检索功能。目前已经有很多应用系统的搜索功能是基于lucene来实现。比如eclipse、idea帮助系统的搜索功能。
  • Lucene能够为文本类型的数据建立索引,只需要把数据转换成文本格式,lucene就可以对文档进行索引和搜索。比如常见的word文档、html文档、pdf文档。首先将文档内容转换成文本格式,交给lucene进行索引,把建立好的索引保存在硬盘或者内存中。然后根据用户输入的查询条件,在索引文件中查找,返回查询结果给用户。

Lucene&搜索引擎区别

  • Lucene是一个全文检索引擎工具包,相当于汽车发动机;搜索引擎基于全文检索实现,是一个可以独立运行的软件产品,相当于汽车。

Lucene官方网站

代码演示

数据库(lucene_db),表(book),直接导入完事


SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `book`
-- ----------------------------
DROP TABLE IF EXISTS `book`;
CREATE TABLE `book` (
  `id` int(11) DEFAULT NULL,
  `bookname` varchar(500) DEFAULT NULL,
  `price` float DEFAULT NULL,
  `pic` varchar(200) DEFAULT NULL,
  `bookdesc` varchar(2000) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of book
-- ----------------------------
INSERT INTO `book` VALUES ('1', 'java从入门到精通', '56', '1.jpg', '《Java从入门到精通》是人民邮电出版社于 2010年出版的图书,由国家863中部软件孵化器主编。以零基础讲解为宗旨,深入浅出地讲解Java的各项技术及实战技能。本书从初学者角度出发,通过通俗易懂的语言、丰富多彩的实例,详细介绍了使用Java语言进行程序开发应该掌握的各方面技术。全书共分28章,包括:初识Java,熟悉Eclipse开发工具,Java 语言基础,流程控制,字符串,数组,类和对象,包装类,数字处理类,接口、继承与多态,类的高级特性,异常处理,Swing程序设计,集合类,I/O输入输出,反射,枚举类型与泛型,多线程,网络通信,数据库操作,Swing表格组件,Swing树组件,Swing其他高级组件,高级布局管理器,高级事件处理,AWT绘图与音频播放,打印技术和企业进销存管理系统等。所有知识都结合具体实例进行介绍,涉及的程序代码给出了详细的注释,可以使读者轻松领会Java程序开发的精髓,快速提高开发技能。.');
INSERT INTO `book` VALUES ('2', 'java web开发', '80', '2.jpg', 'Java Web,是用Java技术来解决相关web互联网领域的技术总和。web包括:web服务器和web客户端两部分。Java在客户端的应用有java applet,不过使用得很少,Java在服务器端的应用非常的丰富,比如Servlet,JSP和第三方框架等等。Java技术对Web领域的发展注入了强大的动力。');
INSERT INTO `book` VALUES ('3', 'lucene从入门到精通', '100', '3.jpg', '本书总结搜索引擎相关理论与实际解决方案,并给出了 Java 实现,其中利用了流行的开源项目Lucene和Solr,而且还包括原创的实现。本书主要包括总体介绍部分、爬虫部分、自然语言处理部分、全文检索部分以及相关案例分析。爬虫部分介绍了网页遍历方法和如何实现增量抓取,并介绍了从网页等各种格式的文档中提取主要内容的方法。自然语言处理部分从统计机器学习的原理出发,包括了中文分词与词性标注的理论与实现以及在搜索引擎中的实用等细节,同时对文档排重、文本分类、自动聚类、句法分析树、拼写检查等自然语言处理领域的经典问题进行了深入浅出的介绍并总结了实现方法。在全文检索部分,结合Lucene 3.0介绍了搜索引擎的原理与进展。用简单的例子介绍了Lucene的最新应用方法。本书包括完整的搜索实现过程:从完成索引到搜索用户界面的实现。本书还进一步介绍了实现准实时搜索的方法,展示了Solr 1.4版本的用法以及实现分布式搜索服务集群的方法。最后介绍了在地理信息系统领域和户外活动搜索领域的应用。');
INSERT INTO `book` VALUES ('4', 'lucene in action传智播客', '90', '4.jpg', '本书深入浅出地介绍了lucene——一个开源的使用java语言编写的全文搜索引擎开发包。它通过浅显的语言、大量的图注、丰富的代码示例,以及清晰的结构为读者呈现出作为优秀开源项目的lucene所体现的强大功能。全书共10章,分为两大部分。第1部分lucene的核心,着重于lucene的核心 api介绍,并按照把lucene集成到程序中的顺序宋组织;第2部分lucene的应用,通过对lucene内置工具的介绍,展示了lucene技术的高级应用和在各种程序语言上的移植。.');
INSERT INTO `book` VALUES ('5', 'Lucene Java精华版', '80', '5.jpg', '本书总结搜索引擎相关理论与实际解决方案,并给出了 Java 实现,其中利用了流行的开源项目Lucene和Solr,而且还包括原创的实现。本书主要包括总体介绍部分、爬虫部分、自然语言处理部分、全文检索部分以及相关案例分析。爬虫部分介绍了网页遍历方法和如何实现增量抓取,并介绍了从网页等各种格式的文档中提取主要内容的方法。自然语言处理部分从统计机器学习的原理出发,包括了中文分词与词性标注的理论与实现以及在搜索引擎中的实用等细节,同时对文档排重、文本分类、自动聚类、句法分析树、拼写检查等自然语言处理领域的经典问题进行了深入浅出的介绍并总结了实现方法。在全文检索部分,结合Lucene 3.0介绍了搜索引擎的原理与进展。用简单的例子介绍了Lucene的最新应用方法。本书包括完整的搜索实现过程:从完成索引到搜索用户界面的实现。本书还进一步介绍了实现准实时搜索的方法,展示了Solr 1.4版本的用法以及实现分布式搜索服务集群的方法。最后介绍了在地理信息系统领域和户外活动搜索领域的应用。');

依赖(pom.xml)

    <packaging>jar</packaging>

    <properties>
        <mysql.version>5.1.47</mysql.version>
        <lucene.version>4.10.3</lucene.version>
        <junit.version>4.12</junit.version>
    </properties>

    <dependencies>
        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <!-- 分词器 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-analyzers-common</artifactId>
            <version>${lucene.version}</version>
        </dependency>
        <!-- 查询解析器 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-queryparser</artifactId>
            <version>${lucene.version}</version>
        </dependency>
        <!-- junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.6</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

Book(实体类)

public class Book {

    private Integer id;
    private String bookName;
    private Double bookPrice;
    private String bookPic;
    private String bookDesc;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public Double getBookPrice() {
        return bookPrice;
    }

    public void setBookPrice(Double bookPrice) {
        this.bookPrice = bookPrice;
    }

    public String getBookPic() {
        return bookPic;
    }

    public void setBookPic(String bookPic) {
        this.bookPic = bookPic;
    }

    public String getBookDesc() {
        return bookDesc;
    }

    public void setBookDesc(String bookDesc) {
        this.bookDesc = bookDesc;
    }
}

BookDao(dao接口)

package dt2008.dao;
import dt2008.domain.Book;
import java.util.List;

public interface BookDao {

    /**
     * 查询所有图书
     * @return
     */
    List<Book> findAll();

}

BookDaoImpl(dao实体类)用的是jdbc技术

package dt2008.dao.impl;

import dt2008.dao.BookDao;
import dt2008.domain.Book;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class BookDaoImpl implements BookDao {
    @Override
    public List<Book> findAll() {
        Connection connection = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;

        List<Book> bookList = new ArrayList<>();
        try{
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");

            //2.获取连接
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/lucene_db","root","root");

            //3.编译sql语句
            stmt = connection.prepareStatement("select * from book");

            //4.执行sql,获取结果集
            rs = stmt.executeQuery();

            //5.封装数据
            while(rs.next()){
                Book book = new Book();

                book.setId(rs.getInt("id"));
                book.setBookName(rs.getString("bookname"));
                book.setBookPrice(rs.getDouble("price"));
                book.setBookPic(rs.getString("pic"));
                book.setBookDesc(rs.getString("bookdesc"));

                bookList.add(book);
            }

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //释放资源
            try {
                rs.close();
                stmt.close();
                connection.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //6.返回数据
        return bookList;

    }
}

索引流程实现(BookDaoTest),BookDaoTest两个方法写在一块的

package dt2008;

import dt2008.dao.BookDao;
import dt2008.dao.impl.BookDaoImpl;
import dt2008.domain.Book;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
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.apache.lucene.util.Version;
import org.junit.Test;

import org.apache.lucene.document.Document;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class BookDaoTest {

    @Test
    public void text02() throws IOException {
        //1.采集原始数据
        BookDao bookDao = new BookDaoImpl();
        List<Book> bookList = bookDao.findAll();

        //2.创建文档对象(Document)
        //一个Document->一行记录  一个Field->记录的一个列
        //2.1 创建Docuement集合
        List<Document> documentList = new ArrayList<>();
        //2.2 遍历原始数据,创建Document对象
        for(Book book:bookList){
            //2.3 创建Docuemnt,封装一个图书对象
            Document document = new Document();
            //2.4 把每个Book的属性封装Docuement的Field中
            /**
             * TextField: 文本域   域特性:是否索引,是否分词,是否存储文档
             *   参数一:Field的名称,该名称用于搜索数据的
             *   参数二:Field的值
             *   参数三:是否存储
             */
            document.add(new TextField("id",book.getId()+"", Field.Store.YES));
            document.add(new TextField("bookName",book.getBookName()+"", Field.Store.YES));
            document.add(new TextField("bookPrice",book.getBookPrice()+"", Field.Store.YES));
            document.add(new TextField("bookPic",book.getBookPic()+"", Field.Store.YES));
            document.add(new TextField("bookDesc",book.getBookDesc()+"", Field.Store.YES));

            documentList.add(document);
        }

        //3. 创建分词器(Analyzer),用于分词
        //StandardAnalyzer: 标准分词器,一个单词作为一个词条
        StandardAnalyzer analyzer = new StandardAnalyzer();

        //4. 创建索引库配置对象(IndexWriterConfig),配置索引库
        //IndexWriterConfig作用:用于设置分词器,设置Lucene版本
        /**
         * 参数一:指定Lucene的版本(注意:和当前环境使用的Lucene版本一致)
         * 参数二:指定分词器
         */
        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_4_10_3,analyzer);

        //5. 创建索引库目录对象(Directory),指定索引库的位置(一般是硬盘的某个目录)
        Directory directory = FSDirectory.open(new File("C:/lucene-4.10.3/index/"));

        //6. 创建索引库操作对象(IndexWriter),把文档对象写入索引库
        /**
         * 参数一:指定索引库的目录
         * 参数二:指定索引库配置对象
         */
        IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);

        //6.1 开始建立文档索引
        for(Document document:documentList){
            //6.2 写出文档
            indexWriter.addDocument(document);
            //6.3 事务提交
            indexWriter.commit();
        }

        //7.释放资源 (IO流)
        indexWriter.close();

    }
}

注意:小编是保存在个文件下的C:/lucene-4.10.3/index/

运行以后就这样的

然后就是读取他的文件信息,在BookDaoTest下面在写个方法,用于读取文件信息

package dt2008;

import dt2008.dao.BookDao;
import dt2008.dao.impl.BookDaoImpl;
import dt2008.domain.Book;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
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.apache.lucene.util.Version;
import org.junit.Test;

import org.apache.lucene.document.Document;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class BookDaoTest {

    @Test
    public void searchIndex() throws Exception {
        //1. 创建分词器对象(Analyzer),用于分词(注意:和建立索引使用的分词器是一样的!)
        StandardAnalyzer analyzer = new StandardAnalyzer();

        //2. 创建查询对象(Query)
        //2.1 创建查询解析器
        /**
         * 参数一:指定需要检索的Field名称
         * 参数二:指定分词器
         */
        QueryParser queryParser = new QueryParser("bookName", analyzer);
        //2.2 创建查询对象,传入关键词
        Query query = queryParser.parse("bookName:java");
        //3. 创建索引库的目录(Directory),指定索引库的位置
        Directory directory = FSDirectory.open(new File("C:/lucene-4.10.3/index/"));
        //4. 创建索引读取对象(IndexReader),把索引数据读取到内存中
        IndexReader indexReader = DirectoryReader.open(directory);
        //5. 创建索引搜索对象(IndexSearcher),执行搜索
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);
        //6. 使用IndexSearcher执行搜索,返回搜索结果集(TopDocs)
        /**
         * 参数一:指定查询对象
         * 参数二:指定前面的取出多少条
         */
        //返回TopDocs搜索结果集对象
        TopDocs topDocs = indexSearcher.search(query, 10);
        //7. 处理结果集
        //7.1 获取索引命中数
        System.out.println("索引命中数:"+ topDocs.totalHits);
        //7.2 获取结果集中的文档数组
        //ScoreDoc: 该对象只包含了检索到的文档的ID(scoreDoc.doc),而没有真实的文档数据
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        for(ScoreDoc scoreDoc:scoreDocs){
            //7.3 通过文档ID获取对应的文档对象(Document)
            Document document = indexSearcher.doc(scoreDoc.doc);

            //7.4 从Document取出每个Field
            System.out.println(document.get("id"));
            System.out.println(document.get("bookName"));
            System.out.println(document.get("bookPrice"));
            System.out.println(document.get("bookPic"));
            System.out.println(document.get("bookDesc"));

            System.out.println("===============华丽分割线===============");
        }

        //8. 释放资源
        indexReader.close();
    }

}

访问后就是这样的

整体BookDaoTest的写法(上面方法是写入,下面方法是读取)

package dt2008;

import dt2008.dao.BookDao;
import dt2008.dao.impl.BookDaoImpl;
import dt2008.domain.Book;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
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.apache.lucene.util.Version;
import org.junit.Test;

import org.apache.lucene.document.Document;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class BookDaoTest {
    //写入
    @Test
    public void text02() throws IOException {
        //1.采集原始数据
        BookDao bookDao = new BookDaoImpl();
        List<Book> bookList = bookDao.findAll();

        //2.创建文档对象(Document)
        //一个Document->一行记录  一个Field->记录的一个列
        //2.1 创建Docuement集合
        List<Document> documentList = new ArrayList<>();
        //2.2 遍历原始数据,创建Document对象
        for(Book book:bookList){
            //2.3 创建Docuemnt,封装一个图书对象
            Document document = new Document();
            //2.4 把每个Book的属性封装Docuement的Field中
            /**
             * TextField: 文本域   域特性:是否索引,是否分词,是否存储文档
             *   参数一:Field的名称,该名称用于搜索数据的
             *   参数二:Field的值
             *   参数三:是否存储
             */
            document.add(new TextField("id",book.getId()+"", Field.Store.YES));
            document.add(new TextField("bookName",book.getBookName()+"", Field.Store.YES));
            document.add(new TextField("bookPrice",book.getBookPrice()+"", Field.Store.YES));
            document.add(new TextField("bookPic",book.getBookPic()+"", Field.Store.YES));
            document.add(new TextField("bookDesc",book.getBookDesc()+"", Field.Store.YES));

            documentList.add(document);
        }

        //3. 创建分词器(Analyzer),用于分词
        //StandardAnalyzer: 标准分词器,一个单词作为一个词条
        StandardAnalyzer analyzer = new StandardAnalyzer();

        //4. 创建索引库配置对象(IndexWriterConfig),配置索引库
        //IndexWriterConfig作用:用于设置分词器,设置Lucene版本
        /**
         * 参数一:指定Lucene的版本(注意:和当前环境使用的Lucene版本一致)
         * 参数二:指定分词器
         */
        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_4_10_3,analyzer);

        //5. 创建索引库目录对象(Directory),指定索引库的位置(一般是硬盘的某个目录)
        Directory directory = FSDirectory.open(new File("C:/lucene-4.10.3/index/"));

        //6. 创建索引库操作对象(IndexWriter),把文档对象写入索引库
        /**
         * 参数一:指定索引库的目录
         * 参数二:指定索引库配置对象
         */
        IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);

        //6.1 开始建立文档索引
        for(Document document:documentList){
            //6.2 写出文档
            indexWriter.addDocument(document);
            //6.3 事务提交
            indexWriter.commit();
        }

        //7.释放资源 (IO流)
        indexWriter.close();

    }

    //读取
    @Test
    public void searchIndex() throws Exception {
        //1. 创建分词器对象(Analyzer),用于分词(注意:和建立索引使用的分词器是一样的!)
        StandardAnalyzer analyzer = new StandardAnalyzer();

        //2. 创建查询对象(Query)
        //2.1 创建查询解析器
        /**
         * 参数一:指定需要检索的Field名称
         * 参数二:指定分词器
         */
        QueryParser queryParser = new QueryParser("bookName", analyzer);
        //2.2 创建查询对象,传入关键词
        Query query = queryParser.parse("bookName:java");
        //3. 创建索引库的目录(Directory),指定索引库的位置
        Directory directory = FSDirectory.open(new File("C:/lucene-4.10.3/index/"));
        //4. 创建索引读取对象(IndexReader),把索引数据读取到内存中
        IndexReader indexReader = DirectoryReader.open(directory);
        //5. 创建索引搜索对象(IndexSearcher),执行搜索
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);
        //6. 使用IndexSearcher执行搜索,返回搜索结果集(TopDocs)
        /**
         * 参数一:指定查询对象
         * 参数二:指定前面的取出多少条
         */
        //返回TopDocs搜索结果集对象
        TopDocs topDocs = indexSearcher.search(query, 10);
        //7. 处理结果集
        //7.1 获取索引命中数
        System.out.println("索引命中数:"+ topDocs.totalHits);
        //7.2 获取结果集中的文档数组
        //ScoreDoc: 该对象只包含了检索到的文档的ID(scoreDoc.doc),而没有真实的文档数据
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        for(ScoreDoc scoreDoc:scoreDocs){
            //7.3 通过文档ID获取对应的文档对象(Document)
            Document document = indexSearcher.doc(scoreDoc.doc);

            //7.4 从Document取出每个Field
            System.out.println(document.get("id"));
            System.out.println(document.get("bookName"));
            System.out.println(document.get("bookPrice"));
            System.out.println(document.get("bookPic"));
            System.out.println(document.get("bookDesc"));

            System.out.println("===============华丽分割线===============");
        }

        //8. 释放资源
        indexReader.close();
    }

}

希望这边文章对您有帮助。

本站资源除特别声明外,转载文章请声明文章出处
东泰博客 » Lucene入门案例

发表评论