查询原理(一)

  从本篇文章开始介绍Lucene查询阶段的内容,由于Lucene提供了几十种不同方式的查询,但其核心的查询逻辑是一致的,该系列的文章通过Query的其中的一个子类BooleanQuery,同时也是作者在实际业务中最常使用的,来介绍Lucene的查询原理。

查询方式

  下文中先介绍几种常用的查询方式的简单应用:

TermQuery

图1:

  图1中的TermQuery描述的是,我们想要找出包含域名(FieldName)为“content”,域值(FieldValue)中包含“a”的域(Field)的文档。

  该查询方式的demo见:https://github.com/LuXugang/Lucene-7.5.0/blob/master/LuceneDemo/src/main/java/lucene/query/TermQueryTest.java

BooleanQuery

图2:

  BooleanQuery为组合查询,图2中给出了最简单的多个TermQuery的组合(允许其他查询方式的组合),上图中描述的是,我们期望的文档必须至少(根据BooleanClause.Occur.SHOULD)满足两个TermQuery中的一个,如果都满足,那么打分更高。

  该查询方式的demo见:https://github.com/LuXugang/Lucene-7.5.0/blob/master/LuceneDemo/src/main/java/lucene/query/BooleanQueryTest.java

WildcardQuery

  该查询方式为通配符查询,支持两种通配符:

  星号通配符描述的是匹配零个或多个字符,问号通配符描述的是匹配一个字符,转义符号用来对星号跟问号进行转移,表示这两个作为字符使用,而不是通配符。

图3:

  问号通配符的查询:

图4:

  图4中的查询会匹配文档3,文档1

  星号通配符的查询:

图5:

  图4中的查询会匹配文档0、文档1、文档2、文档3

  转义符号的使用:

图6:

  图4中的查询会匹配文档3

  该查询方式的demo见:https://github.com/LuXugang/Lucene-7.5.0/blob/master/LuceneDemo/src/main/java/lucene/query/WildcardQueryTest.java

PrefixQuery

  该查询方式为前缀查询:

图7:

  图7中的PrefixQuery描述的是,我们想要找出包含域名为“content”,域值的前缀值为"go"的域的文档。

  以图3为例子,图7的查询会匹配文档0、文档1

  该查询方式的demo见:https://github.com/LuXugang/Lucene-7.5.0/blob/master/LuceneDemo/src/main/java/lucene/query/PrefixQueryTest.java

FuzzyQuery

  该查询方式为模糊查询,使用编辑距离来实现模糊匹配,下面的查询都是以图3作为例子

图8:

  图8中的各个参数介绍如下:

  图8中的查询会匹配文档0、文档1

图9:

  图9中的方法最终会调用图8的构造方法,即maxExpansions跟transpositions的值会使用默认值:

  图9中的查询会匹配文档0、文档1

图10:

  图10中的方法最终会调用图8的构造方法,即prefixLength、maxExpansions跟transpositions的值会使用默认值:

  图10中的查询会匹配文档0、文档1、文档2、文档3

图11:

  图11中的方法最终会调用图8的构造方法,即maxEdits、maxEprefixLength、maxExpansions跟transpositions的值会使用默认值:

  图10中的查询会匹配文档0、文档1、文档2、文档3

  该查询方式的demo见:https://github.com/LuXugang/Lucene-7.5.0/blob/master/LuceneDemo/src/main/java/lucene/query/FuzzyQueryTest.java

RegexpQuery

  该查询方式为正则表达式查询,使用正则表达式来匹配域的域值:

图12:

  图12中的RegexpQuery描述的是,我们想要找出包含域名(FieldName)为“content”,域值(FieldValue)中包含以"g"开头,以"d"结尾,中间包含零个或多个"o"的域(Field)的文档。

  图12中的查询会匹配文档0、文档1、文档2

  该查询方式的demo见:https://github.com/LuXugang/Lucene-7.5.0/blob/master/LuceneDemo/src/main/java/lucene/query/RegexpQueryTest.java

PhraseQuery

图13:

  该查询方式为短语查询:

图14:

  图14中,我们定义了两个Term,域值分别为"quick"、"fox",期望获得的这样文档:文档中必须包含这两个term,同时两个term之间的相对位置为2 (3 - 1),并且允许编辑距离最大为1,编辑距离用来调整两个term的相对位置(必须满足)。

  故根据图13的例子,图14中的查询会匹配文档0、文档1、文档2

图15:

  图15中,我们另编辑距离为0,那么改查询只会匹配文档0、文档1

图16:

  图16中,我们另编辑距离为4,此时查询会匹配文档0、文档1、文档2、文档3

  这里简单说下短语查询的匹配逻辑:

  该查询方式的demo见:https://github.com/LuXugang/Lucene-7.5.0/blob/master/LuceneDemo/src/main/java/lucene/query/PhraseQueryTest.java

 

TermRangeQuery

图17:

  该查询方式为范围查询:

图18:

  图18中的查询会匹配文档1、文档2、文档3

  在后面的文章中会详细介绍TermRangeQuery,对这个查询方法感兴趣的同学可以先看Automaton,它通过确定型有穷自动机的机制来找到查询条件范围内的所有term。

  该查询方式的demo见:https://github.com/LuXugang/Lucene-7.5.0/blob/master/LuceneDemo/src/main/java/lucene/query/TermRangeQueryTest.java

PointRangeQuery

图19:

  该查询方式为域值是数值类型的范围查询(多维度查询):

图20:

 

  PointRangeQuery用来实现多维度查询,在图19中,文档0中域名为"coordinate",域值为"2, 8"的IntPoint域,可以把该域的域值看做是直角坐标系中一个x轴值为2,y轴值为8的一个坐标点。

  故文档1中域名为"coordinate"的域,它的域值的个数描述的是维度的维数值。

  在图20中,lowValue描述的是x轴的值在[1, 5]的区间,upValue描述的y轴的值在[4, 7]的区间,我们期望找出由lowValue和upValue组成的一个矩形内的点对应的文档。

图21:

  图21中红框描述的是lowValue跟upValue组成的矩形。

  故图20中的查询会匹配文档1

  在后面的文章中会详细介绍PointRangeQuery的查询过程,对这个查询方法感兴趣的同学可以先看Bkd-Tree以及索引文件之dim&&dii,这两篇文章介绍了在索引阶段如何存储数值类型的索引信息。

  该查询方式的demo见:https://github.com/LuXugang/Lucene-7.5.0/blob/master/LuceneDemo/src/main/java/lucene/query/PointRangeQueryTest.java

结语

  

点击下载附件