• (二)Luence——代码实现索引及搜索


    完成需求:使用Lucene完成对数据库中图书信息的索引和搜索功能。

    1. 环境准备及工程搭建

    1.1 环境准备

    mysql5.5+java8+lucene4.10.3(目前最新7.0.1,这里够用就好)

    需要注意:lucene从4.8版本以后,必须使用jdk1.7及以上。

    1.2 工程搭建

    • Mysql驱动包
    • Analysis的包
    • Core
    • QueryParser
    • Junit(非必须)

    2. 索引

    2.1 采集数据

    Book.java(省略get&set方法)

    public class Book {
            // 图书ID
            private Integer id;
            // 图书名称
            private String name;
            // 图书价格
            private Float price;
            // 图书图片
            private String pic;
            // 图书描述
            private String description;
            ······
            ·····
    }

    BookDaoImpl.java(实现数据库连接和查询)

    public class BookDaoImpl implements BookDao {
        @Override
        public List<Book> queryBooks() {
            // 数据库链接
            Connection connection = null// 预编译statement
            PreparedStatement preparedStatement = null;
            // 结果集
            ResultSet resultSet = null;
            // 图书列表
            List<Book> list = new ArrayList<Book>();
            try {
                // 加载数据库驱动
                Class.forName("com.mysql.jdbc.Driver");
                // 连接数据库
                connection = DriverManager.getConnection(
                        "jdbc:mysql://localhost:3306/solr", "root", "123");
                // SQL语句
                String sql = "SELECT * FROM book";
                // 创建preparedStatement
                preparedStatement = connection.prepareStatement(sql);
                // 获取结果集
                resultSet = preparedStatement.executeQuery();
                // 结果集解析
                while (resultSet.next()) {
                    Book book = new Book();
                    book.setId(resultSet.getInt("id"));
                    book.setName(resultSet.getString("name"));
                    book.setPrice(resultSet.getFloat("price"));
                    book.setPic(resultSet.getString("pic"));
                    book.setDescription(resultSet.getString("description"));
                    list.add(book);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return list;
        }
    }

    2.2 创建索引

    创建索引流程

                           

    IndexWriter是索引过程的核心组件,通过IndexWriter可以创建新索引、更新索引、删除索引操作。IndexWriter需要通过Directory对索引进行存储操作。

    Directory描述了索引的存储位置,底层封装了I/O操作,负责对索引进行存储。它是一个抽象类,它的子类常用的包括FSDirectory(在文件系统存储索引)、RAMDirectory(在内存存储索引)。

    @Test
        public void createIndex() throws Exception{
            //采集数据
            BookDao dao = new BookDaoImpl();
            List<Book> list = dao.queryBooks();
            
            //将采集到的数据封装到Document对象中
            List<Document> docList = new ArrayList<>();
            Document document;
            for (Book book : list) {
                document = new Document();
                // store:如果是yes,则说明存储到文档域中
                // 图书ID
                Field id = new TextField("id", book.getId().toString(), Store.YES);
                // 图书名称
                Field name = new TextField("name", book.getName(), Store.YES);
                // 图书价格
                Field price = new TextField("price", book.getPrice().toString(), Store.YES);
                // 图书图片地址
                Field pic = new TextField("pic", book.getPic(), Store.YES);
                // 图书描述
                Field description = new TextField("description", book.getDescription(), Store.YES);
    
                // 将field域设置到Document对象中
                document.add(id);
                document.add(name);
                document.add(price);
                document.add(pic);
                document.add(description);
    
                docList.add(document);
            }
            
                    // a)创建分词器,标准分词器(分析文档,对文档中的Field域进行分词)
                    Analyzer analyzer = new StandardAnalyzer();
    
                    // b)创建IndexWriterConfig对象
                    IndexWriterConfig cfg = new IndexWriterConfig(Version.LUCENE_4_10_3, analyzer);
                    // c)创建索引库目录,指定索引库的地址
                    File indexFile = new File("D:\DBIndex\");
                    Directory directory = FSDirectory.open(indexFile);
                    // d)创建IndexWriter对象
                    IndexWriter writer = new IndexWriter(directory, cfg);
    
                    // e)通过IndexWriter对象将Document写入到索引库中
                    for (Document doc : docList) {
                        writer.addDocument(doc);
                    }
                    // f)关闭writer
                    writer.close();
        }

    2.3 分词

    2.3.1 Lucene中分词主要分为两个步骤分词过滤

    分词field域中的内容一个个的分词

    过滤将分好的词进行过滤比如去掉标点符号大写转小写词的型还原(复数转单数、过去式转成现在式)、停用词过滤

    停用词单独应用没有特殊意义的词比如的英文中的this is a the等等

    例:要分词的内容

    Lucene is a Java full-text search engine.     

      经过分词后:

    lucene     java  full  text  search  engine

    2.3.2 参考org.apache.lucene.analysis.standard.standardAnalyzer的部分源码了解分词过程

    @Override
      protected TokenStreamComponents createComponents(final String fieldName, final Reader reader) {
        final StandardTokenizer src = new StandardTokenizer(getVersion(), reader);
        src.setMaxTokenLength(maxTokenLength);
        TokenStream tok = new StandardFilter(getVersion(), src);
        tok = new LowerCaseFilter(getVersion(), tok);
        tok = new StopFilter(getVersion(), tok, stopwords);
        return new TokenStreamComponents(src, tok) {
          @Override
          protected void setReader(final Reader reader) throws IOException {
            src.setMaxTokenLength(StandardAnalyzer.this.maxTokenLength);
            super.setReader(reader);
          }
        };
      }

    2.3.3 语汇单元的生成过程

    从一个Reader字符流开始,创建一个基于ReaderTokenizer分词器,经过三个TokenFilter生成语汇单元Token

    同一个域中相同的语汇单元(Token)对应同一个Term(词),它记录了语汇单元的内容及所在域的域名等,还包括来该token出现的频率及位置。

    • 不同的域中拆分出来的相同的单词对应不同的term
    • 相同的域中拆分出来的相同的单词对应相同的term

    例如:图书信息里面,图书名称中的java和图书描述中的java对应不同的term

     2.4 使用luke工具查看索引

    Luke作为Lucene工具包中的一个工具(http://www.getopt.org/luke/),可以通过界面来进行索引文件的查询、修改。

    打开Luke方法:

    • 命令运行cmd运行:java  -jar lukeall-4.10.3.jar
    • 手动执行双击lukeall-4.10.3.jar

     创建索引后,打开Luke,Path选为索引库的地址,确定即能查看到索引

    luke应用

     2.5 搜索流程

    同数据库的sql一样,lucene全文检索也有固定的语法。  最基本的有比如:AND, OR, NOT 等(需要大写)

    举个例子,用户想找一个description中包括java关键字和lucene关键字的文档。

    它对应的查询语句:description:java AND lucene 

    2.5.1 使用luke搜索的例子

    2.5.2 代码实现

                                 

    @Test
        public void indexSearch() throws Exception {
            // 创建query对象
            // 使用QueryParser搜索时,需要指定分词器,搜索时的分词器要和索引时的分词器一致
            // 第一个参数:默认搜索的域的名称
            QueryParser parser = new QueryParser("description", new StandardAnalyzer());
    
            // 通过queryparser来创建query对象
            // 参数:输入的lucene的查询语句(关键字一定要大写)
            Query query = parser.parse("description:java AND lucene");
    
            // 创建IndexSearcher
            // 指定索引库的地址
            File indexFile = new File("D:\DBIndex\");
            Directory directory = FSDirectory.open(indexFile);
            IndexReader reader = DirectoryReader.open(directory);
            IndexSearcher searcher = new IndexSearcher(reader);
    
            // 通过searcher来搜索索引库
            // 第二个参数:指定需要显示的顶部记录的N条
            TopDocs topDocs = searcher.search(query, 10);
    
            // 根据查询条件匹配出的记录总数
            int count = topDocs.totalHits;
            System.out.println("匹配出的记录总数:" + count);
            // 根据查询条件匹配出的记录
            ScoreDoc[] scoreDocs = topDocs.scoreDocs;
    
            for (ScoreDoc scoreDoc : scoreDocs) {
                // 获取文档的ID
                int docId = scoreDoc.doc;
    
                // 通过ID获取文档
                Document doc = searcher.doc(docId);
                System.out.println("商品ID:" + doc.get("id"));
                System.out.println("商品名称:" + doc.get("name"));
                System.out.println("商品价格:" + doc.get("price"));
                System.out.println("商品图片地址:" + doc.get("pic"));
                System.out.println("==========================");
                // System.out.println("商品描述:" + doc.get("description"));
            }
            // 关闭资源
            reader.close();
        }
  • 相关阅读:
    第8组 Beta(2/6)(赵红霞)
    第8组 Beta (1/6)(赵红霞)
    第8组 Alpha(6/6)(赵红霞)
    第8组 Alpha(5/6)(赵红霞)
    第8组 Alpha(4/6)(赵红霞)
    第8组 Alpha(3/6)(赵红霞)
    第8组 Alpha(2/6)(赵红霞)
    Windows炫酷桌面钢铁侠主题 雨滴 Rainmeter
    blob 视频无法解析下载?不存在的,来瞅瞅这个方法
    java C C++ .net ps 安卓 等各种教学视频免费送
  • 原文地址:https://www.cnblogs.com/zjfjava/p/7637983.html
Copyright © 2020-2023  润新知