在文章软删除softDeletes(一)中我们介绍了软删除的一些应用,从本篇文章开始,将根据索引(index)、flush/commit、段的合并、搜索这几个不同的阶段来介绍跟软删除相关的内容。
索引(index)
阅读本小结内容必须掌握文章文档的增删改(四)中的知识点,故下文中出现的一些名词不会作详细的介绍。
索引(index)这个阶段,即文档的增删改的阶段,由于软删除属于删除操作,故对应的删除信息会被添加到全局的deleteQueue中,deleteQueue中存放了四种类型的删除信息,这四种删除信息用下图中的Node对象来描述:
图1:
上图中的四种删除信息通过IndexWriter类中提供的方法生成:
- QueryArrayNode:deleteDocuments(Querys)
- TermArrayNode:deleteDocuments(Terms)
- DocValuesUpdatesNode:updateBinaryDocValue( )、updateNumericDocValue( )、updateDocValues( )、softUpdateDocument( )、softUpdateDocuments( )
- TermNode:updateDocument(Term, Document)、updateDocuments( Term, Documents)
由上文可以看出,软删除对应的删除信息将会由DocValuesUpdatesNode来描述,
我们通过一个例子来看下DocValuesUpdatesNode中描述了哪些删除信息:
图2:
图2中,第56行执行了软删除的操作,它对应的删除信息DocValuesUpdatesNode包含如下信息:
图3:
DocValuesUpdatesNode中包含了两个对象:next、item,其中next用来指向deleteQueue中下一个删除信息(见文章文档的增删改(四)),item(NumericDocValuesUpdate对象)中的type描述了使用NUMERIC类型的DocValues来描述被软删除的文档,item中的term描述了满足被软删除的文档的条件,即包含域名为"abc"、域值为"document3"的文档都会被软删除。
上述DocValuesUpdatesNode的信息我们可以看出,我们获得了满足软删除的条件,但是没有指出软删除的作用范围(作用域),例如在图2中,文档3也满足被软删除的条件,但是这篇文档是在第56行的软删除操作之后添加的,那么这次的软删除不能作用(apply)到这篇文档,即这次的软删除操作只能对文档1生效,故我们还需要根据DocValuesUpdatesNode的信息进一步完善删除信息,即添加软删除的作用范围,不同的删除信息在完善删除信息后用下列的容器来描述(Lucene 7.5.0):
- Map<Term,Integer> deleteTerms :TermArrayNode、TermNode
- Map<Query,Integer> deleteQueries:QueryArrayNode
- Map<String,LinkedHashMap<Term,NumericDocValuesUpdate>> numericUpdates:DocValuesUpdatesNode
- Map<String,LinkedHashMap<Term,BinaryDocValuesUpdate>> binaryUpdate:DocValuesUpdatesNode
BufferedUpdates类、deleteTerms、deleteQueries的内容在文章文档的增删改(四)中已经作出了介绍,不赘述。
如果DocValuesUpdatesNode中item中的type为NUMERIC,那么对应生成numericUpdates,如果item中的type为BINARY,那么对应生成binaryUpdate。
numericUpdates
numericUpdates容器的key描述的是图3中,item中的field的值,而容器的value则是又一个LinkedHashMap的容器,该容器的key为一个term,例如图3中的item的term的值,而value则是图3中的item。
在文章构造IndexWriter对象(一)中我们说到,一个IndexWriter通过IndexWriterConfig配置只能设置一个软删除域,并且是个不可变配置
,那么为什么numericUpdates使用Map存储,并且key为软删除域的值?
- 上文中我们说到,IndexWriter类中提供的updateBinaryDocValue( )、updateNumericDocValue( )、updateDocValues( )方法(这三个方法为更新DocValues的操作)对应生成的删除信息跟软删除操作softUpdateDocument( )、softUpdateDocuments( )一样都是用DocValuesUpdatesNode来描述,故也使用同一个numericUpdates来完善删除信息,所以numericUpdates容器的key不一定就是软删除的域。
我们同样的以一个例子来介绍:
图4:
图4的例子中,既有updateNumericDocValue(),又有softDocument()的操作,那么这两个操作对应在numericUpdates中的删除信息如下所示:
图5:
我们接着继续介绍为什么numericUpdates容器的value是一个LinkedHashMap结构,先给出源码中对这种设计的注释:
图6:
注释中讲述了使用LinkedHashMap结构的两个原因:
- 原因一:在不同的term之间,即LinkedHashMap的不同的key,如果一篇文档中包含的term满足多个软删除操作中的term条件(见文章软删除softDeletes(一)),那么根据LinkedHashMap的插入有序的特点,这篇文档用最后一个软删除操作中的DocValues来描述该文档被软删除了
- 原因二:在相同的term之间,如果多次调用的软删除中的term条件是一样的,那么可以进行去重,并且选取作用范围(作用域)最大的那个(下面的例子会介绍)
我们继续用一个例子来介绍上述的原因一:
图7:
图7中,第56、61行执行了两次软删除操作,并且文档0都满足这两个软删除的条件,由于第61行的软删除操作晚于第56行,所以文档0将用61行中的域名为"softDeleteField"、域值为4的NumericDocValues来描述它被软删除了,至于使用这个DocValues来描述被软删除的用途,将在后面的文章中介绍。
我们接着通过一个例子介绍上述的原因二:
图8:
图8中,第56、64行执行了两次软删除操作,并且他们的软删除条件是一样的,即被软删除的文档中需要包含域名为"abc"、域值为"document1"的信息,那么第56行的软删除对应的删除信息将被第66行的软删除对应的删除信息替换。
图8中两次软删除对应在numericUpdates容器中的信息有什么不同,为什么会发生替换?
我们直接给出这两次软删除的对应在numericUpdates容器中的信息来做介绍:
图9:
图10:
图9、图10中,docIDUpto描述的是删除信息的作用范围(作用域),图9中docIDUpto的值为2,它描述了从删除信息的作用范围为文档号区间为[0, 2)、图10中的docIDUpto的值为5,它描述了从删除信息的作用范围为文档号区间为[0, 4),故图10中的作用范围包含了图9中的删除范围,这样就能过滤掉相同term条件的软删除操作。
注意点
上文中我们说到,updateBinaryDocValue( )、updateNumericDocValue( )、updateDocValues( )、softUpdateDocument( )、softUpdateDocuments( )的操作在索引期间使用相同的方式来存储删除信息,这使得我们用softUpdateDocument( )需要注意一个问题,如果该方法中用来描述文档被软删除的DocValues的域名不是IndexWriter的配置中定义的软删除域,那么这次软删除操作就会转变为DocValues的更新操作,我们通过下面的例子来说明:
图11:
图11中,如果update为true,那么我们执行软删除操作,注意的是59行用来描述文档被软删除的DocValues的域名"docValuesField"不是38行的设置的软删除域”softDeleteField“,故这次的软删除操作转化为DocValues的更新操作,那么文档1中域名为"docValuesFiled"的NumericDocValuesField的域值"5"会被更新为"3",故搜索结果在按照"docValuesField"排序之后, 如下所示:
图12:
可见,文档1并没有被软删除,图11的demo看这里:https://github.com/LuXugang/Lucene-7.5.0/blob/master/LuceneDemo/src/main/java/lucene/softDeletes/SoftDeletesTest3.java 。
结语
本文中,我们介绍了Lucene7.5.0版本中,在索引期间跟软删除相关的一些内容,即使用numericUpdates、binaryUpdate两个容器存储删除信息,然而在Lucene8.4.0中,取消了这两个容器,使用了其他的方法存储删除信息,这块内容将在下篇文章中展开。
点击下载附件