有的时候,我们一开始不可能准确地知道搜索的关键字在 Solr 中查询出的结果是什么,因此,Solr 还提供了几种类型的模糊查询。模糊匹配会在索引中对关键字进行非精确匹配。例如,有的人可能想要搜索某个前缀开始的单词(称为通配符查询),或者想要查询和关键字有一两个字母不相同的单词(称为模糊查询或编辑距离查询),或者你想要查询两个关键字,并且这两个关键字之间的距离不会大于某个最大值(称为临近查询)。总的说来,模糊匹配是查询中的一个强大的工具。

通配符查询

在 Solr 中最普遍使用的模糊查询就是使用通配符。假设你想要查询以 offic 开始的文档。下面列举出这个查询的几个版本:

  • 查询语句: office OR officer OR official OR officiate OR … 这个列表中的单词是所有你以 offic 开头的单词。

    因为你需要找到的所有匹配都在 Solr 索引中。因此,你可以使用星号(*)作为通配符来执行相同的功能:

  • 查询语句: offi* 匹配  office, officer, official 等等。

    除了放在关键字的最后,通配符也可以放到关键字中间,例如,如果你想要同时匹配 officer 和 offer:

  • 查询语句: off*r 匹配 offer,officer,officiator 等。

    星号通配符(*)表示匹配 0 个或多个字符。如果你只需要匹配一个字符,那么可以使用问号(?)通配符:

  • 查询语句: off?r  匹配 offer 但是不匹配 officer。

以通配符为头进行查询

在 Solr 中使用通配符相当强大。但是,使用通配符进行查询也会带来很大的开销。一旦使用统配符的查询,那么在关键字中第一个通配符之前的部分需要在反向索引中全部查询出来。那后,每个查询出来的结果在逐一进行检查,看是否符合查询条件。正是因为这样,所以在统配符之前的字符越多,那么查询将会越快。例如,使用 engineer*  进行查询将不会带来很高的开销(因为这个查询在反向索引中不会找到太多的匹配),但是 e* 进行查询的开销就相当大,它将会匹配所有 e 开头的单词。

如果使用通配符开头的话,开销也会相当大。例如,你需要查询 ing 结尾的单词(像 caring,liking 和 smiling),那么将会带来严重的性能问题:

  • 查询语句: *ing

如果你真的需要进行这样的查询,那么有一个现成的解决方案,这个解决方案就是添加 ReversedWildcardFilterFactory 到你的字段类型的分析链中(详细内容以后会讲到)。

ReversedWildcardFilterFactory 将会插入两条记录到 Solr 的索引中(一条是单词的正向文本内容,一条是单词的反向文本内容):

  • 索引:caring/#gnirac liking/#gnikil smiling/#gnilims

当提交了 *ing 的查询之后,Solr 知道使用索引中的反向内容去查询,这样由通配符开头带来的性能问题就转换成了普通的通配符查询问题。

但是要注意,如果将这个特性打开的话,那么在 Solr 索引中的所有关键字都将会由两条索引记录,这无疑增加了索引的大小并且降低了整个查询的速度。因此,不建议打开这个功能,除非你的应用程序真的非常需要。

关于使用统配符查询的最后一点就是使用通配符只能对单独的关键字进行插叙,而不能对短语进行查询,例如:

  • 正常: softwar* eng?neering
  • 不正常:”softwar* eng?neering”

如果你需要在短语中使用通配符,你将要把整个短语作为一个关键字存储到索引中,我们将会在以后讲解这个功能。

范围查询

Solr 也提供了在已知值之间的范围查询。当你需要查询某个范围之间的子集的时候,这个功能非常有用。例如,如果你只想查询 2012 年 2 月 2 日到 2012 年 8 月 2 日这六个月之间的文档,那么可以执行下面的查询:

  • 查询语句:created:[2012-02-01T00:00.0Z TO 2012-08-02T00:00.0Z]

范围查询的语法结构也可以用在其它字段上:

  • 查询语句: yearsOld:[18 TO 21] 匹配:18, 19, 20, 21
  • 查询语句:title:[boat TO boulder] 匹配:boat, boil, book, boulder,等
  • 查询语句:price:[12.99 TO 14.99] 匹配: 12.99, 13.000009, 14.99, 等

上面的范围查询都是放在一对方括号中,这成为被包含的范围查询语法(闭区间)。Solr 也支持不被包含的范围查询语法(开区间),这需要把查询范围放到大括号中:

  • 查询语句:yearsOld:{18 TO 21} 匹配:19 和 20 但是不匹配 18 或 21
  • 查询语句:yearsOld:{18 TO 21} Matches 19 and 20 but not 18 or 21

虽然看起来有点奇怪,但是 Solr 也提供了半包含的范围查询语法(半开区间):

  • 查询语句: yearsOld:[18 TO 21} 匹配:18, 19, 20, 但是不匹配 21

范围查询的效率比查询单个关键字要低,但是为某个特定的范围进行检索提供了巨大的灵活性。需要注意的是,使用范围查询的返回结果是按照 Solr 索引进行排序的,也就是说是按照字典顺序。如果你创建了一个文本字段来存储数字,那么这些数字的返回顺序应该是这样:1, 11, 111, 12, 120, 13, 等。如果是数字类型的字段,那么将使用特殊的方式来进行索引这样可以弥补这个问题,但是要明白一点,在 Solr 索引中进行排序依赖于写入索引的时候,字段中的数据是如何被处理的。详细内容以后会说明。

模糊/编辑距离查询

对于很多搜索应用来说,很重要的功能是不仅仅需要精确匹配用户的文本内容。而且还允许一些灵活的变化,比如一些用户的拼写错误或相同单词的其它变体。Solr 通过基于 Damerau-Levenshtein 距离的编辑距离测量来支持这个功能,它将容忍 80% 以上的拼写错误。

Solr 提供的模糊编辑距离查询需要用到波浪符号(~):

  • 查询语句: administrator~ 匹配: adminstrator, administrater, administratior,等

这个查询不仅匹配原始的关键字(administrator),还有其它与原始关键字有 2 个编辑距离的关键字。一个编辑距离表示增加,删除,取代或交换一个任意字符。关键字 adminstrator (在第六个字母出少了字符“i”)和原始关键字之间相差一个编辑距离,因为它删除了一个字符。同样 sadministrator 和原始关键字之间也是相差一个编辑距离,因为它在前面添加了一个字符。administratro 也与原始关键字有一个编辑距离,因为它将最后两个字符交换了顺序。

在编辑距离查询中也可以精确指定编辑距离:

  • 查询语句:administrator~1 匹配一个编辑距离以内的内容。
  • 查询语句:administrator~2 匹配两个编辑距离以内的内容(如果没有提供编辑距离的话,这个就是默认值)。
  • 查询语句:administrator~N 匹配 N 个编辑距离以内的内容。

注意,任何编辑距离大于 2 的查询将会使查询速度变得很慢。如果编辑距离在 2 以内,那么将会使用很高效率的 Levenshtein 自动机(Levenshtein automaton),但是如果编辑距离大于 2,将会退回到更慢的编辑距离实现。

临近查询

在前面,我们看到了编辑距离查询是如何查找相似的关键字,而不是进行精确匹配。编辑距离的概念适用于关键字中字符的变换或短语中各个单词之间的变化。

如果你想要通过 Solr 的索引查询公司中所有员工的档案。一种方法是枚举出公司中所有可能的职位:

  • 查询语句:”chief executive officer” OR “chief financial officer” OR “chief

    marketing officer” OR “chief technology officer” OR …

当然,这种查询的前提是你需要知道公司中所有可能的职位,这当然不现实。另外的一种解决方案是单独搜索每个关键字:

  • 查询语句: chief AND officer

这将会匹配所有可能的用例,但是同时也会匹配所有包含了这两个关键字的文档。例如:One chief concern arising from the incident was the safety of the police officer on duty。这个文档明显不符合我们的要求,但是如果使用上面的查询语句,那么将会返回这个文档。

Solr 提供了解决这种问题的方案:临近插叙。在上面的例子中,比较好的策略是请求 Solr 返回所有包含了关键字 chief 和关键字 officer 临近的文档。这可以通过下面的查询语句样例来实现:

  • 查询语句: “chief officer”~1 
    解释:chief 和 officer 之间最多只能有一个距离 
    例子:”chief executive officer”, “chief financial officer”
  • 查询语句:”chief officer”~2 
    解释:chief 和 officer 之间最多只能有两个编辑距离 
    例子:”chief business development officer”, “officer chief”
  • 查询语句:”chief officer”~N 
    解释:查询 chief 和 officer 之间有 N 个编辑距离。

事实上,对短语进行精确匹配的查询语句 “chief  development  officer” 很容易改写成  “chief development officer”~0。这两个查询都返回相同的结果,因为在第二个查询语句中,编辑距离设置为 0,所以和精确查询得到的结果是相同的。这两种机制都需要使用到 Solr 中存储的关键字位置(前面的文章介绍过)来计算编辑距离。还有一点需要注意的是,临近查询并不是完全按照编辑距离的定义来进行查询,因为它的查询结果中,所有的关键字都必须存在。而编辑距离查询的定义中,可以对关键字进行删除和修改。

但是其它的编辑距离定义依旧保留,例如增加和换位。顺着这条线,你可能会注意到,你需要设置 2 进行临近查询的时候(”chief officer”~2)才能查询出文本 officer chief。这是因为第一次编辑将 chief 和 officer 修改成相同的位置;第二次编辑将 chief 才能将 chief 编辑到 officer 后面。这也再次说明了临近查询使用的并不是真正的编辑距离(在编辑距离中,位置互换的编辑距离只能算 1)。

solr之~模糊查询【转】的更多相关文章

  1. solr之~模糊查询

    有的时候,我们一开始不可能准确地知道搜索的关键字在 Solr 中查询出的结果是什么,因此,Solr 还提供了几种类型的模糊查询.模糊匹配会在索引中对关键字进行非精确匹配.例如,有的人可能想要搜索某个前 ...

  2. Solr基础理论【倒排索引,模糊查询】

    一.简介 现有的许多不同类型 的技术系统,如关系型数据库.键值存储.操作磁盘文件的map-reduce[映射-规约]引擎.图数据库等,都是为了帮助用户解决颇具挑战性的数据存储与检索问题而设计的.而搜索 ...

  3. Solr学习笔记——查询

    1.进入Solr管理界面http://localhost:8983/solr/ 可以看到Query中有若干的参数,其意义如下(参考:http://www.jianshu.com/p/3c4cae5de ...

  4. Solr分组聚合查询之Group

    摘要: Solr对结果的分组处理除了facet还可以使用group.Solr的group是根据某一字段对结果分组,将每一组内满足查询的结果按顺序返回. Group对比Facet Group和Facet ...

  5. Mybatis框架的模糊查询(多种写法)、删除、添加(四)

    学习Mybatis这么多天,那么我给大家分享一下我的学习成果.从最基础的开始配置. 一.创建一个web项目,看一下项目架构 二.说道项目就会想到需要什么jar 三.就是准备大配置链接Orcl数据库 & ...

  6. js—模糊查询

    首先要明白什么是模糊查询(废话又来了),就是根据关键字把列表中符合关键字的一项或某项罗列出来,也就是要检查列表的每一项中是否含有关键字,因此抽象一下就是一个字符串中是否含有某个字符或者字符串. 以下例 ...

  7. Solr实战:使用Hue+Solr实现标签查询

    公司最近在研究多条件组合查询方案,Google的一位技术专家Sam和我们讨论了几个备选方案. Sam的信: 我做了进一步研究,目前有这么几种做法: 1) 最直接粗暴,只做一个主index,比如按行业+ ...

  8. mybatis : trim标签, “等于==”经验, CDATA标签 ,模糊查询CONCAT,LIKE

    一.My Batis trim标签有点类似于replace效果. trim 属性, prefix:前缀覆盖并增加其内容 suffix:后缀覆盖并增加其内容 prefixOverrides:前缀判断的条 ...

  9. combobox实现模糊查询自动填充

    利用winform设计软件界面时,经常用到combobox控件,但有时需要绑定数据表中的数据,更进一步,需要实现对数据表中数据的模糊查询功能.本文就讲讲述如何用C#实现combobox下拉列表的模糊查 ...

随机推荐

  1. org.json.JSONException: A JSONObject text must begin with '{' at character 1 of {解决方法

    在使用java读取一个本地的json配置文件的时候,产生了这个异常:org.json.JSONException: A JSONObject text must begin with '{' at c ...

  2. STM32通过调用库函数进行编程

    1.调用库函数编程和直接配置寄存器编程的差别: 2.CMSIS标准: 3.STM32库函数的组织: 4.程序例举: 调用库函数实现通过USART发送数据(26个大写的英文字母) 首先:在主函数部分先要 ...

  3. 基于docker容器搭建fastdfs分布式文件系统

    本次环境的搭建参考了 https://blog.csdn.net/qq_43455410/article/details/84797814, 感谢博主. 主要流程如下: 1. 下载fastdfs镜像 ...

  4. 原生js 平滑滚动到页面的某个位置

    window.scrollTo() 语法1:  window.scrollTo(x-coord,y-coord) x-coord 是文档中的横轴坐标. y-coord 是文档中的纵轴坐标. 例子: w ...

  5. Android大牛的博客

    1 谦虚的天下:http://www.cnblogs.com/qianxudetianxia/ 2 csdn博文精选:http://www.csdn.net/article/2011-08-30/30 ...

  6. HDU1255 覆盖的面积 —— 求矩形交面积 线段树 + 扫描线 + 离散化

    题目链接:https://vjudge.net/problem/HDU-1255 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input输入数据的第一行是一个正整数T(1<= ...

  7. cell.getCellType有几种

    CellType 类型 值CELL_TYPE_NUMERIC 数值型 0CELL_TYPE_STRING 字符串型 1CELL_TYPE_FORMULA 公式型 2CELL_TYPE_BLANK 空值 ...

  8. java 类属性、方法加载的顺序

    1.静态变量 2.静态代码块 3.局部代码块 4.构造函数 5.普通代码块 6.静态方法 7.普通方法 8.普通属性

  9. PHPExcel使用收藏

    注意:PHP7版本中phpexcel导出文件是提示找不到文件,需修改PHPExcel目录下的calculation目录下的Functions.php的581行  去掉break; 下面是总结的几个使用 ...

  10. 【HAOI 2015】 树上操作

    [题目链接] 点击打开链接 [算法] 树链剖分 子树的DFS序是连续的一段! [代码] #include<bits/stdc++.h> using namespace std; #defi ...