• Lucene第一篇【介绍Lucene、快速入门】


    什么是Lucene??

    Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包,由资深全文检索专家Doug Cutting所撰写,它是一个全文检索引擎的架构,提供了完整的创建索引和查询索引,以及部分文本分析的引擎,Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎,Lucene在全文检索领域是一个经典的祖先,现在很多检索引擎都是在其基础上创建的,思想是相通的。

    Lucene是根据关健字来搜索的文本搜索工具,只能在某个网站内部搜索文本内容,不能跨网站搜索

    既然谈到了网站内部的搜索,那么我们就谈谈我们熟悉的百度、google那些搜索引擎又是基于什么搜索的呢….

    这里写图片描述

    这里写图片描述

    从图上已经看得很清楚,baidu、google等搜索引擎其实是通过网络爬虫的程序来进行搜索的


    为什么我们要用Lucene?

    在介绍Lucene的时候,我们已经说了:Lucene又不是搜索引擎,仅仅是在网站内部进行文本的搜索。那我们为什么要学他呢???

    我们之前编写纳税服务系统的时候,其实就已经使用过SQL来进行站内的搜索..

    既然SQL能做的功能,我们还要学Lucene,为什么呢???

    我们来看看我们用SQL来搜索的话,有什么缺点:

    • (1)SQL只能针对数据库表搜索,不能直接针对硬盘上的文本搜索
    • (2)SQL没有相关度排名
    • (3)SQL搜索结果没有关健字高亮显示
    • (4)SQL需要数据库的支持,数据库本身需要内存开销较大,例如:Oracle
    • (5)SQL搜索有时较慢,尤其是数据库不在本地时,超慢,例如:Oracle

    这里写图片描述

    我们来看看在baidu中搜索Lucene为关键字搜索出的内容是怎么样的:

    这里写图片描述

    以上所说的,我们如果使用SQL的话,是做不到的。因此我们就学习Lucene来帮我们在站内根据文本关键字来进行搜索数据


    我们如果网站需要根据关键字来进行搜索,可以使用SQL,也可以使用Lucene…那么我们Lucene和SQL是一样的,都是在持久层中编写代码的。。

    这里写图片描述

    快速入门

    接下来,我们就讲解怎么使用Lucene了…..在讲解Lucene的API之前,我们首先来讲讲Lucene存放的究竟是什么内容…我们的SQL使用的是数据库中的内存,在硬盘中为DBF文件…那么我们Lucene内部又是什么东西呢??

    Lucene中存的就是一系列的二进制压缩文件和一些控制文件,它们位于计算机的硬盘上,
    这些内容统称为索引库,索引库有二部份组成:

    • (1)原始记录
      • 存入到索引库中的原始文本,例如:我是钟福成
    • (2)词汇表
      • 按照一定的拆分策略(即分词器)将原始记录中的每个字符拆开后,存入一个供将来搜索的表

    也就是说:Lucene存放数据的地方我们通常称之为索引库,索引库又分为两部分组成:原始记录和词汇表….

    原始记录和词汇表

    当我们想要把数据存到索引库的时候,我们首先存入的是将数据存到原始记录上面去….

    又由于我们给用户使用的时候,用户使用的是关键字来进行查询我们的具体记录。因此,我们需要把我们原始存进的数据进行拆分!将拆分出来的数据存进词汇表中

    词汇表就是类似于我们在学Oracle中的索引表,拆分的时候会给出对应的索引值。

    一旦用户根据关键字来进行搜索,那么程序就先去查询词汇表中有没有该关键字,如果有该关键字就定位到原始记录表中,将符合条件的原始记录返回给用户查看

    我们查看以下的图方便理解:

    这里写图片描述

    到了这里,有人可能就会疑问:难道原始记录拆分的数据都是一个一个汉字进行拆分的吗??然后在词汇表中不就有很多的关键字了???

    其实,我们在存到原始记录表中的时候,可以指定我们使用哪种算法来将数据拆分,存到词汇表中…..我们的图是Lucene的标准分词算法,一个一个汉字进行拆分。我们可以使用别的分词算法,两个两个拆分或者其他的算法。

    编写第一个Lucene程序

    首先,我们来导入Lucene的必要开发包:

    • lucene-core-3.0.2.jar【Lucene核心】
    • lucene-analyzers-3.0.2.jar【分词器】
    • lucene-highlighter-3.0.2.jar【Lucene会将搜索出来的字,高亮显示,提示用户】
    • lucene-memory-3.0.2.jar【索引库优化策略】

    创建User对象,User对象封装了数据….

    
    /**
     * Created by ozc on 2017/7/12.
     */
    public class User {
    
    
        private String id ;
        private String userName;
        private String sal;
    
        public User() {
    
        }
        public User(String id, String userName, String sal) {
            this.id = id;
            this.userName = userName;
            this.sal = sal;
        }
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public String getUserName() {
            return userName;
        }
    
        public void setUserName(String userName) {
            this.userName = userName;
        }
    
        public String getSal() {
            return sal;
        }
    
        public void setSal(String sal) {
            this.sal = sal;
        }
    }
    

    我们想要使用Lucene来查询出站内的数据,首先我们得要有个索引库吧!于是我们先创建索引库,将我们的数据存到索引库中

    创建索引库的步骤:

    • 1)创建JavaBean对象
    • 2)创建Docment对象
    • 3)将JavaBean对象所有的属性值,均放到Document对象中去,属性名可以和JavaBean相同或不同
    • 4)创建IndexWriter对象
    • 5)将Document对象通过IndexWriter对象写入索引库中
    • 6)关闭IndexWriter对象
    
        @Test
        public void createIndexDB() throws Exception {
    
            //把数据填充到JavaBean对象中
            User user = new User("1", "钟福成", "未来的程序员");
    
            //创建Document对象【导入的是Lucene包下的Document对象】
            Document document = new Document();
    
            //将JavaBean对象所有的属性值,均放到Document对象中去,属性名可以和JavaBean相同或不同
    
    
            /**
             * 向Document对象加入一个字段
             * 参数一:字段的关键字
             * 参数二:字符的值
             * 参数三:是否要存储到原始记录表中
             *      YES表示是
             *      NO表示否
             * 参数四:是否需要将存储的数据拆分到词汇表中
             *      ANALYZED表示拆分
             *      NOT_ANALYZED表示不拆分
             *
             * */
            document.add(new Field("id", user.getId(), Field.Store.YES, Field.Index.ANALYZED));
            document.add(new Field("userName", user.getUserName(), Field.Store.YES, Field.Index.ANALYZED));
            document.add(new Field("sal", user.getSal(), Field.Store.YES, Field.Index.ANALYZED));
    
            //创建IndexWriter对象
            //目录指定为E:/createIndexDB
            Directory directory = FSDirectory.open(new File("E:/createIndexDB"));
    
            //使用标准的分词算法对原始记录表进行拆分
            Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
    
            //LIMITED默认是1W个
            IndexWriter.MaxFieldLength maxFieldLength = IndexWriter.MaxFieldLength.LIMITED;
            /**
             * IndexWriter将我们的document对象写到硬盘中
             *
             * 参数一:Directory d,写到硬盘中的目录路径是什么
             * 参数二:Analyzer a, 以何种算法来对document中的原始记录表数据进行拆分成词汇表
             * 参数三:MaxFieldLength mfl 最多将文本拆分出多少个词汇
             *
             * */
            IndexWriter indexWriter = new IndexWriter(directory, analyzer, maxFieldLength);
    
            //将Document对象通过IndexWriter对象写入索引库中
            indexWriter.addDocument(document);
    
            //关闭IndexWriter对象
            indexWriter.close();
    
        }
    

    这里写图片描述

    程序执行完,我们就会在硬盘中见到我们的索引库。

    这里写图片描述

    那我们现在是不知道记录是否真真正正存储到索引库中的,因为我们看不见。索引库存放的数据放在cfs文件下,我们也是不能打开cfs文件的

    于是,我们现在用一个关键字,把索引库的数据读取。看看读取数据是否成功。

    根据关键字查询索引库中的内容:

    • 1)创建IndexSearcher对象
    • 2)创建QueryParser对象
    • 3)创建Query对象来封装关键字
    • 4)用IndexSearcher对象去索引库中查询符合条件的前100条记录,不足100条记录的以实际为准
    • 5)获取符合条件的编号
    • 6)用indexSearcher对象去索引库中查询编号对应的Document对象
    • 7)将Document对象中的所有属性取出,再封装回JavaBean对象中去,并加入到集合中保存,以备将之用
    
        @Test
        public void findIndexDB() throws Exception {
    
            /**
             * 参数一: IndexSearcher(Directory path)查询以xxx目录的索引库
             *
             * */
            Directory directory = FSDirectory.open(new File("E:/createIndexDB"));
            //创建IndexSearcher对象
            IndexSearcher indexSearcher = new IndexSearcher(directory);
    
            //创建QueryParser对象
            /**
             * 参数一: Version matchVersion 版本号【和上面是一样的】
             * 参数二:String f,【要查询的字段】
             * 参数三:Analyzer a【使用的拆词算法】
             * */
            Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
            QueryParser queryParser = new QueryParser(Version.LUCENE_30, "userName", analyzer);
    
            //给出要查询的关键字
            String keyWords = "钟";
    
            //创建Query对象来封装关键字
            Query query = queryParser.parse(keyWords);
    
            //用IndexSearcher对象去索引库中查询符合条件的前100条记录,不足100条记录的以实际为准
            TopDocs topDocs = indexSearcher.search(query, 100);
    
            //获取符合条件的编号
    
            for (int i = 0; i < topDocs.scoreDocs.length; i++) {
    
                ScoreDoc scoreDoc = topDocs.scoreDocs[i];
                int no = scoreDoc.doc;
                //用indexSearcher对象去索引库中查询编号对应的Document对象
                Document document = indexSearcher.doc(no);
    
                //将Document对象中的所有属性取出,再封装回JavaBean对象中去
                String id = document.get("id");
                String userName = document.get("userName");
                String sal = document.get("sal");
    
                User user = new User(id, userName, sal);
                System.out.println(user);
    
            }

    这里写图片描述

    效果:

    这里写图片描述


    进一步说明Lucene代码

    我们的Lucene程序就是大概这么一个思路:将JavaBean对象封装到Document对象中,然后通过IndexWriter把document写入到索引库中。当用户需要查询的时候,就使用IndexSearcher从索引库中读取数据,找到对应的Document对象,从而解析里边的内容,再封装到JavaBean对象中让我们使用

    这里写图片描述


  • 相关阅读:
    C# String 前面不足位数补零的方法
    bootstrap-wysiwyg这个坑
    PRECONDITION_FAILED
    JdbcTemplate in()传参
    Mysql Specified key was too long; max key length is 767 bytes
    获取两日期之前集合并转为String类型的集合
    SQL里的concat() 以及group_concat() 函数的使用
    spring boot如何打印mybatis的执行sql
    MockMvc 进行 controller层单元测试 事务自动回滚 完整实例
    找到 Confluence 6 的日志和配置文件
  • 原文地址:https://www.cnblogs.com/zhong-fucheng/p/7202897.html
Copyright © 2020-2023  润新知