Lucene教程(四) 索引的更新和删除

这篇文章是基于上一篇文章来写的,使用的是IndexUtil类,下面的例子不在贴出整个类的内容,只贴出具体的方法内容。

3.5版本:

先写了一个check()方法来查看索引文件的变化:

    /**
     * 检查一下索引文件
     */
    public static void check() {
        IndexReader indexReader = null;
        try {
            Directory directory = FSDirectory.open(new File("F:/test/lucene/index"));
            indexReader = IndexReader.open(directory);
            // 通过reader可以有效的获取到文档的数量
            // 有效的索引文档
            System.out.println("有效的索引文档:" + indexReader.numDocs());
            // 总共的索引文档
            System.out.println("总共的索引文档:" + indexReader.maxDoc());
            // 删掉的索引文档,其实不恰当,应该是在回收站里的索引文档
            System.out.println("删掉的索引文档:" + indexReader.numDeletedDocs());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (indexReader != null) {
                    indexReader.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

那么就下来就先跑一下建立索引方法,然后在执行以下check()方法,看看结果:

有效的索引文档:3
总共的索引文档:3
删掉的索引文档:0

接下来我想删除一个索引,例子如下:

    /**
     * 删除索引
     */
    public static void delete() {
        IndexWriter indexWriter = null;
        try {
            Directory directory = FSDirectory.open(new File("F:/test/lucene/index"));
            Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_35);
            IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_35, analyzer);
            indexWriter = new IndexWriter(directory, indexWriterConfig);
            /**
             * 参数是一个选项,可以是一个Query,也可以是一个term,term是一个精确查找的值
             *
             * 此时删除的文档并不会被完全删除,而是存储在一个回收站中的,可以恢复
             */

            // 方式一:通过Term删除

            /**
             * 注意Term构造器的意思,第一个参数为Field,第二个参数为Field的值
             */
            indexWriter.deleteDocuments(new Term("id", "1"));

            // 方式二:通过Query删除

            /**
             * 这里就要造一个Query出来,删掉查处的索引
             */
            QueryParser queryParser = new QueryParser(Version.LUCENE_35, "content", analyzer);
            // 创建Query表示搜索域为content包含Lucene的文档
            Query query = queryParser.parse("Lucene");

            // indexWriter.deleteDocuments(query);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (indexWriter != null) {
                    indexWriter.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

看看测试:

    @Test
    public void testDelete() {
        IndexUtil.delete();
        IndexUtil.check();
    }

执行过后:

有效的索引文档:2
总共的索引文档:3
删掉的索引文档:1

此时被删掉的文档跑到了回收站中,并没有被彻底删除,我们上面使用的是删term的方式,那么使用query删行不行呢,那么现在把注释换一换:

            // indexWriter.deleteDocuments(new Term("id", "1"));

            // 方式二:通过Query删除

            /**
             * 这里就要造一个Query出来,删掉查处的索引
             */
            QueryParser queryParser = new QueryParser(Version.LUCENE_35, "content", analyzer);
            // 创建Query表示搜索域为content包含Lucene的文档
            Query query = queryParser.parse("Lucene");

            indexWriter.deleteDocuments(query);

再跑一下测试方法:

有效的索引文档:1
总共的索引文档:3
删掉的索引文档:2

看看,被删除的文档又多了一个,因为我们query查出的文档和id为1的文档不是同一个,目前了解了删除的两种方式怎么使用了吧。

我现在发现删错了,想恢复怎么办,那么我们就来看看怎么恢复删除的索引:

    /**
     * 恢复删除的索引
     */
    public static void unDelete() {
        // 使用IndexReader进行恢复
        IndexReader indexReader = null;
        try {
            Directory directory = FSDirectory.open(new File("F:/test/lucene/index"));
            // 恢复时,必须把IndexReader的只读(readOnly)设置为false
            // 索引没有改变可以使用true,但现在是恢复删除的索引,显然是改变过的,所以只能是false
            indexReader = IndexReader.open(directory, false);
            indexReader.undeleteAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (indexReader != null) {
                    indexReader.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

跑一下测试:

    @Test
    public void testUnDelete() {
        IndexUtil.unDelete();
        IndexUtil.check();
    }

结果为:

有效的索引文档:3
总共的索引文档:3
删掉的索引文档:0

全部恢复了吧,很不错吧

但是我现在有发现刚才没有删错,我要把索引彻底删除,怎么弄呢,我们回过头来再试,我现在吧删除索引的两种方式的注释都打开,执行一下删除方法是不是得到这样的结果啊:

有效的索引文档:1
总共的索引文档:3
删掉的索引文档:2

然后看看彻底删除的代码:

    /**
     * 强制删除
     */
    public static void forceDelete() {
        IndexWriter indexWriter = null;
        try {
            Directory directory = FSDirectory.open(new File("F:/test/lucene/index"));
            Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_35);
            IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_35, analyzer);
            indexWriter = new IndexWriter(directory, indexWriterConfig);
            indexWriter.forceMergeDeletes();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (indexWriter != null) {
                    indexWriter.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

执行一下测试代码:

    @Test
    public void testForceDelete() {
        IndexUtil.forceDelete();
        IndexUtil.check();
    }

结果如下:

有效的索引文档:1
总共的索引文档:1
删掉的索引文档:0

此时两个索引文档被彻底的删掉了。这么长都在讲删除的事,那么Lucene是怎么更新索引的呢,记下来看看是如何更新索引的:

注:先把索引文件删除,重新建索引

    /**
     * 更新索引
     */
    public static void update() {
        IndexWriter indexWriter = null;
        try {
            Directory directory = FSDirectory.open(new File("F:/test/lucene/index"));
            Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_35);
            IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_35, analyzer);
            indexWriter = new IndexWriter(directory, indexWriterConfig);
            /**
             * Lucene并没有提供更新,这里的更新操作其实是如下两个操作的合集 先删除之后再添加
             */
            Document document = new Document();
            document.add(new Field("id", "11", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
            document.add(new Field("author", authors[0], Field.Store.YES, Field.Index.NOT_ANALYZED));
            document.add(new Field("title", titles[0], Field.Store.YES, Field.Index.ANALYZED));
            document.add(new Field("content", contents[1], Field.Store.NO, Field.Index.ANALYZED));
            indexWriter.updateDocument(new Term("id", "1"), document);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (indexWriter != null) {
                    indexWriter.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

注意上边这段代码,我使用的content是id为2的content,它包含“Lucene”,我一会要用它测试,注意比对结果

此时执行一下更新索引:

    @Test
    public void testUpdate() {
        IndexUtil.update();
        IndexUtil.check();
    }

结果为:

有效的索引文档:3
总共的索引文档:4
删掉的索引文档:1

结果是这样的,惊讶吗,我们一起来算算,有效的文档删掉一个添加一个是不是3个,没错吧,总共的文档数是三个加一个,引文删掉的文档也算啊,没有彻底删掉,在回收站里,然后我们执行一下search()方法,看看结果:

    /**
     * 搜索
     */
    public static void search() {
        IndexReader indexReader = null;
        try {
            // 1、创建Directory
            Directory directory = FSDirectory.open(new File("F:/test/lucene/index"));
            // 2、创建IndexReader
            indexReader = IndexReader.open(directory);
            // 3、根据IndexReader创建IndexSearch
            IndexSearcher indexSearcher = new IndexSearcher(indexReader);
            // 4、创建搜索的Query
            // 使用默认的标准分词器
            Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_35);

            // 在content中搜索Lucene
            // 创建parser来确定要搜索文件的内容,第二个参数为搜索的域
            QueryParser queryParser = new QueryParser(Version.LUCENE_35, "content", analyzer);
            // 创建Query表示搜索域为content包含Lucene的文档
            Query query = queryParser.parse("Lucene");

            // 5、根据searcher搜索并且返回TopDocs
            TopDocs topDocs = indexSearcher.search(query, 10);
            // 6、根据TopDocs获取ScoreDoc对象
            ScoreDoc[] scoreDocs = topDocs.scoreDocs;
            for (ScoreDoc scoreDoc : scoreDocs) {
                // 7、根据searcher和ScoreDoc对象获取具体的Document对象
                Document document = indexSearcher.doc(scoreDoc.doc);
                // 8、根据Document对象获取需要的值
                System.out.println("id : " + document.get("id"));
                System.out.println("author : " + document.get("author"));
                System.out.println("title : " + document.get("title"));
                /**
                 * 看看content能不能打印出来,为什么?
                 */
                System.out.println("content : " + document.get("content"));
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (indexReader != null) {
                    indexReader.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    @Test
    public void testSearch() {
        IndexUtil.search();
    }
id : 2
author : Tony
title : Hello Lucene
content : null
id : 11
author : Darren
title : Hello World
content : null

查出来了两条,说明更新成功了

我再把id为3的索引也更新一下:

Document document = new Document();
            document.add(new Field("id", "11", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
            document.add(new Field("author", authors[0], Field.Store.YES, Field.Index.NOT_ANALYZED));
            document.add(new Field("title", titles[0], Field.Store.YES, Field.Index.ANALYZED));
            document.add(new Field("content", contents[1], Field.Store.NO, Field.Index.ANALYZED));
            indexWriter.updateDocument(new Term("id", "3"), document);

执行一下update()方法,看看结果:

有效的索引文档:3
总共的索引文档:5
删掉的索引文档:2

问题来了,随着索引文件更新次数的增加,索引文件是不是会越来越多啊,那我们是不是有办法合并一下优化一下呢,下面来看Lucene是怎么合并索引文件的:

    /**
     * 合并索引
     */
    public static void merge() {
        IndexWriter indexWriter = null;
        try {
            Directory directory = FSDirectory.open(new File("F:/test/lucene/index"));
            Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_35);
            IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_35, analyzer);
            indexWriter = new IndexWriter(directory, indexWriterConfig);
            // 会将索引合并为2段,这两段中的被删除的数据会被清空
            /**
             * 特别注意:
             *
             * 此处Lucene在3.5之后不建议使用,因为会消耗大量的开销,Lucene会根据情况自动处理的
             */

            // 把索引合并为两段
            indexWriter.forceMerge(2);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (indexWriter != null) {
                    indexWriter.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

执行一下测试:

    @Test
    public void testMerge() {
        IndexUtil.merge();
        IndexUtil.check();
    }

结果为:

有效的索引文档:3
总共的索引文档:3
删掉的索引文档:0

索引文件数恢复正常了,这里有个问题,Lucene的合并索引方法或优化索引方法不建议人为调用,会消耗很多资源,并且Lucene会自动优化索引,索引不用担心索引文件一直变大变多这个问题。

4.5版本:

5.0版本:

4.5版本和5.0版本稍后更新

时间: 2024-10-09 15:17:54

Lucene教程(四) 索引的更新和删除的相关文章

pymongo创建索引、更新、删除

pymongo创建索引.更新.删除 索引创建 ## collection 为数据集合collection.create_Index({'需创建索引字段': 1})collection.ensure_Index({'需创建索引字段': 1})## 获取索引信息,数据库中使用db.getCollection('tablename').getIndexes() 更新 # 更新匹配到的第一条数据collection.update_one(k, {'$set': v})# 更新匹配到的所有数据collec

Lucene教程(三) 索引域选项

通过上两篇的学习,想必已经入了门了,今天来看索引域选项中的几个值得设置 先来看一个构造器: /** * Create a field by specifying its name, value and how it will * be saved in the index. Term vectors will not be stored in the index. * * @param name The name of the field * @param value The string to

CRL快速开发框架系列教程四(删除数据)

本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框架系列教程四(删除数据) CRL快速开发框架系列教程五(使用缓存) CRL快速开发框架系列教程六(分布式缓存解决方案) CRL快速开发框架系列教程七(使用事务) CRL快速开发框架系列教程八(使用CRL.Package) CRL快速开发框架系列教程九(导入/导出数据) CRL快速开发框架系列教程十(

SQL Server索引进阶:第十三级,插入,更新,删除

在第十级到十二级中,我们看了索引的内部结构,以及改变结构造成的影响.在本文中,继续查看Insert,update,delete和merge造成的影响.首先,我们单独看一下这四个命令. 插入INSERT 当向表中插入一行数据的时候,不管表是堆表还是聚集索引表,肯定会在表的索引中插入一个入口,过滤索引除外.这么做的时候,SQL Server使用索引键的值从根页到叶子层页,到达叶子层页之后,检查页的可用空间,如果有足够的空闲空间,新的入口就会被插入适当的位置. 最终,SQL Server可能会试图向一

mySQL教程 第5章 插入 更新与删除数据

第5章 插入 更新与删除数据 使用SQL Manager管理工具连接到schoolDB.由于三张表都设置了主键,因此,以下练习中插入的记录,主键不能重. 插入数据 1. 练习:为表的所有字段插入数据 为表中所有字段插入数据,可以不用指定列 其中的into可以省去 insert into TStudent values ('00008','白安','男','132302197604044565','19760404', '[email protected]','JAVA','20120803')

Lucene教程具体解释

注明:本文是由本人在开发有关基于lucene资源检索系统时的一点总结,当中一部分是自己依据开发过程自己总结的,也有部分是摘自网络,因无法获取当时摘文的地址,所以在此没有写源地址. 转载请声明出处 Lucene-3.0.0配置 一.Lucene开发环境配置 step1.Lucene开发包下载 step2.Java开发环境配置 step3.Tomcat安装 step4.Lucene开发环境配置 解压下载的lucene-3.0.0.zip,能够看到lucene-core-3.0.0.jar和lucen

Lucene教程

一:简单的示例 1.1:生成索引 1.1.1:Field.Store和Field.Index 1.1.2:为数字生成索引 1.1.3:为索引加权 1.1.4:为日期生成索引 1.2:查询 1.2.1:介绍IndexReader 1.3:删除 1.3.1:还原删除的文档 1.3.2:清空回收站时面的数据 1.4:更新 前言:本教程用于Lucene3.5,Maven地址为 <dependency> <groupId>org.apache.lucene</groupId> &

Elasticsearch入门教程(四):Elasticsearch文档CURD

原文:Elasticsearch入门教程(四):Elasticsearch文档CURD 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/vbirdbest/article/details/79217590 一: 新增文档POST /{index}/{type} 或 PUT /{index}/{type}/{id} 注意:新增文档时可以显式指定id,id可以是数字也可以是字符串,如果不显示指

Oracle查询优化-插入、更新与删除

--插入.更新与删除 --1.插入新纪录 --1.1.建立测试表 DROP TABLE TEST; CREATE TABLE TEST( C1 VARCHAR2(10) DEFAULT '默认1', C2 VARCHAR2(10) DEFAULT '默认2', C3 VARCHAR2(10) DEFAULT '默认3', C4 DATE DEFAULT SYSDATE ); --1.2.增加数据 INSERT INTO TEST(C1,C2,C3) VALUES(DEFAULT,NULL,'手输