这节内容有:
1.solr和传统的的数据库技术有什么区别
2.solr内部索引结构
3.Solr执行复杂查询怎样用术语,短语,和模糊匹配
4.solr怎样计算最匹配的文档得分
5.怎么衡量返回匹配结果和所有结果
6.怎样格式化你的内容为非结构化文档
6.solr怎么扩展服务器去处理十亿级文档和查询
现在我们已经启动solr,理解搜索引擎怎么工作和为什么要选择solr去存储检索你的文件时是很重要的,我们这章目标就是给你提供一个理论基础,以便你理解和最大化使用solr.
如果你已经在搜索方面混了好长时间了,你可以跳过这章的一些内容。这节内容会帮你理解最先进的主题,最大化改善你的搜索质量。
虽然本章的内容是普遍适用于大多数搜索引擎,我们更侧重于solr的实现。在本章末尾,你将对solr的内部索引过程有一个扎实的理解。还有solr如何进行复杂的判断和模糊查询,solr默认的评分模型工作原理,solr如何面对数十亿的数据量进行快速查找。
我们先来讨论一下在solr搜索背后的一些核心概念。包括索引怎么工作,搜索引擎怎么匹配查询和文档。
3.1.搜索,匹配和查找内容
许多系统都设计用来帮助我们解决具有挑战性的数据存储和检索问题,如:关系数据库,key value 储存,操作在磁盘上的文件的map-reduce 引擎,图形数据库等等...在搜索引擎中,solr设计用来解决某一类问题————需要搜索大量的非结构化文本,返回最相关的结果。
在这一节,我们将讨论现代搜索引擎的最核心特性。包括搜索“文档”的解释。倒排索引的概述。这个倒排索引可以实现任意复杂的术语、短语和部分匹配查询。
3.1.1. 文档(document)是什么概念?
在第2节,我们把文档post到solr,然后运行示例搜索,所以这不是我们第一次提到文档(documents)。我们要有一个扎实的理解,关于什么信息我们可以放在solr上和如何使信息结构化。
Solr是一个文件存储和检索引擎,提交Solr处理的每条记录都是一个文档。一个文档可以是报纸上的一条文章,一个简历或社会简介,或者,极端情况下 -- 一整本书。
一个文档包含多个值域(fields),每个值域都被模式化成一个特定类型:string, tokenized text, Boolean, date/time, lat/long, etc。
潜在的字段类型的数量是无限的,因为一个值域的构成直接影响到solr对这个值域的处理和索引的建立。每个值域都被定义到solr的 schema.xml中。
列表3.1 展示了一个例子。
Listing 3.1 solr文档例子
<doc>
<field name=" id">company123</field>
<field name="companycity">Atlanta</field>
<field name="companystate">Georgia</field>
<field name="companyname">Code Monkeys R Us, LLC</field>
<field name="companydescription">we write lots of code</field>
<fie ld name="lastmodified">201 3-06-01T1 5:26:3 7Z</field>
</doc>
当我们搜索时,我们能按照这些字段搜索,Solr会返回给我们匹配的结果
请注意,虽然solr有每一个文档的schema,,但这并不是无模式,每一个值域类型都必须定义,每一个值域的名称在schema.xml都得唯一。每份文档不必包含所有值域。solr可以自动猜字段类型,在它第一次接收文件的一个新的字段名。这是通过检查在该领域的数据类型来完成的。solr有肯能会猜错,所有预定义字段类型是推荐的,
一个文档就是多个值域的集合,并符合schema。文档的每个值域都有它自己这种类型的内容分析,该分析的结果被保存到一个搜索索引中,以便稍后检索。从一个Solr查询返回的主要搜索结果是包含一个或多个值域的文档(document).
3.1.2.基本的搜索问题
在我们介绍搜索在solr中是怎么工作之前,很有必要来理解一下搜索的基本问题。
比如你的任务是创建搜索功能帮助用户搜索书,你最初的原型可能看起来像图3.1
图3.1
想象一下现在有个用户要找书,他输入 buying a home 。对于这个搜索你理想的结果是可能是这样的,表 3.1
Table 3.1.输入“buying a home”
潜在的相关书籍:
The Beginner’s Guide to Buying a House
How to Buy Your First House
Purchasing a Home
Becoming a New Home Owner
Buying a New Home
Decorating Your Home
所有其他书的列表,在table 3.2 列出来了。我们认为这是用户不想要的。
A Fun Guide to Cooking
How to Raise a Child
Buying a New Car
如果用传统的关系数据库区实现这个需求,会是这样的。
SELECT * FROM Books WHERE Name = 'buying a new home';
使用这种方法的问题是,在您的图书目录中没有任何一本书的书名准确匹配客户类型的文本,结果就是用户找不到任何一本书。此外,客户只会看到匹配完整输入的查询结果。这是用户想要的么?
或者另外一种方法是一个字一个字的搜索:
SELECT * FROM Books WHERE Name LIKE '%buying%' AND Name LIKE '%a%' AND Name LIKE '%home%';
对于前面这个查询,传统数据库付出代价较高。因为 like用不到数据库索引。
表 3.3 从数据库里查询的结果,需要匹配每一个字段。
匹配的书:
Buying a New Home
不匹配的书:
The Beginner’s Guide to Buying a House
How to Buy Your First House
Purchasing a Home
Becoming a New Home Owner
A Fun Guide to Cooking
How to Raise a Child
Buying a New Car
Decorating Your Home
当然,你或许会认为,匹配用户输入的每一个单词太严格了。你或许会写下面更灵活的查询:
SELECT * FROM Books WHERE Name LIKE '%buying%' OR Name LIKE '%a%' OR Name LIKE '%home%';
这个查询的结果在表3.4 ,你会发现查询结果变多了,因为这个取了查询的最大公约数。甚至书名中包含一个a字,也会返回。前面的示例,会返回所有的匹配结果,甚至是 “a” 的匹配结果,但是我们不期望这种结果,因为其他关键词更重要。
表 3.4
匹配的书
A Fun Guide to Cooking
Decorating Your Home
How to Raise a Child
Buying a New Car
Buying a New Home
The Beginner’s Guide to Buying a House
Purchasing a Home
Becoming a New Home owner
不匹配的书
How to Buy Your First House
第一个查询结果太少,第二个查询结果导致很多不相关的书被找到,
这些例子显示了这种实现的几个难题:
1.无法分词
2.不能理解语言状态变化,比如“buying” 和“buy.”
3.不能辨别相近意思的词,比如 “buying” 和 “purchasing” ,“home” 和“house.”
4.有些不重要的词比如“a”,没法过滤,还有更多类似的词“all” 或"any"
5.在结果中没有关联排序,很显然匹配多次的应该比匹配一次的结果,放在更前面
如果书籍的数量变的很多,查询速度就会变的很慢很慢。因为查询必须扫描每本书的标题,以查找部分匹配,而不是使用索引查找单词。
搜索引擎Solr在解决此类问题的功能简直闪瞎人的眼球,Solr是能够进行文本分析和搜索查询来确定文本相似的词,理解和匹配同义词,去掉不重要的词“a,” “the,” and “of,”并根据匹配进行评分,最相近的结果总是第一个返回,你的客户不必通过翻页无数的相关结果发现他们所期待的内容。Solr完成这一切都是用索引匹配内容。这个倒排索引是搜索引擎如何工作的核心。
3.1.3. 倒排索引
Solr使用Lucene的倒排索引实现快速搜索能力,在查询时间上还额外提供了bells and whistles( as well as many of the additional bells and whistles it provides at query time),当我们进入Lucene 内部数据结构,重点是理解倒排索引的高级结构,我们推荐《Lucene in Action》,有中文版。
回顾我们以前的书搜索例子,我们可以感觉出来索引是怎么匹配每一个单元对应文档的,看表3.5
Table 3.5. 多个文本文档映射到一个倒排索引,右边的表包含一个倒排索引,显示了每一个单元,随着它的位置,从左表的原始文档中。
Original documents Lucene’s inverted index
Doc # Content field Term Doc # (Continued)...
1 A Fun Guide toCooking a 1,3,4,5,6,7,8 home house 2,5,7,8 2 Decorating Your Home beginner’s 8 how new 6,9
3 How to Raise a Child buy 9 owner 4,5,8 8
4 Buying a New Car buying 4,5,6 purchasing
5 Buying a New Home car 4 raise the to 1.6.9
6 The Beginner’s Guide to Buying a House child 3 your 2,9
7 Purchasing a Home cooking 1 new 3,9
8 Becoming a New Home Owner decorating 2
9 How to Buy Your First House
尽管多文档在传统的数据库的表现会包含一个文档id,匹配一个或多个内容领域包含所有的词/单元到这个文件。
倒排索引翻转模型,匹配语料库中的每一个单元到文档出现的每个地方,从表3.5你可以看出来,原始输入文本以空格上进行拆分,每个单词被转换为将小写文本插入到倒排索引中。但其他一切都保持不变。值得注意的是,可能会有许多许多额外的文本转换,不仅仅是这些简单的。在内容分析过程中,可以修改、添加或删除项,在第6节我们将详细讨论。
最后倒排索引应注意的细节
(1).每个在索引的单元匹配一个或多个文档。
(2).在倒排索引中的单元按字典顺序排序,比如b开头的就排在 c开头前面。
表3.5大大简化了倒排索引,我们在 第3.1.6节中科院看到额外的信息可以存储在索引以提高查询和Solr的得分能力。
在下个章节你会看到,lucence的倒排索引结构 最大限度地提高速度和灵活性,基于搜索的关键词。
3.1.4. 单元,短语和布尔逻辑
现在我们已经看了lucene里的倒排索引的大致内容,让我们跳转到一个查询的机制,如何使用这个索引来查找匹配文件。在这一章,我们将学习到在倒排索引中查找单元和短语的基本知识,还有利用布尔逻辑和模糊查询来提供这些查询能力,我们回到书籍搜索的例子,现在我们来输入“new house”来看看。
图3.2
当插入Lucene索引时,内容域中所有的文本被分解成单个的单元,现在来了一个查询,您需要从几个选项中选择查询索引
(1)搜索两个不同的单元,new和house,要求两者都匹配
(2)搜索两个不同的单元,要求只能有一个匹配
(3)搜索一个确切的短语“new house”
这些选项都是有效的,取决于你会怎么做。由于solr和Lucene的强大,这些用布尔逻辑很快就可以实现
查询单元
让我们先选择一个选项,将查询分为多个条件,要求他们全部匹配。用两种方式可以办到。
(1)+new +house
(2) new AND house
这两者在逻辑上是相同的,+符号是一元运算符,意思是查询结果必须匹配改单元,AND关键字是一个二进制运算符,它意味着该查询的一部分,紧接着它的一部分,紧接着它都是必需的。
可选单元
与之相对,solr也支持OR.意思是查询条件有一个符合就行,默认情况下空格就代表OR,如下
• new house
• new OR house
否定单元
要求结果不能匹配一些单元
• new house –rental
• new house NOT rental
在这些查询中,没有包含该词的文档将返回
Solr的默认操作符
而在Solr默认配置假定一个单元或短语本身是一个可选的项。可以用 q.op参数指定,
/select/?q=new house&q.op=OR
/select?q=new house&q.op=AND
短语
solr不仅支持单条件搜索,它也可以搜索短语,确保多个短语在一起出现:
• "new home" OR "new house"
• "3 bedrooms" AND "walk in closet" AND "granite countertops"
分组表达式
除了前面的查询表达式,solr支持的最终基本布尔结构是单元分组,单词和其他的查询表达式。通过分组使用括号,Solr查询语法可以代表任意复杂的查询比如下面的例子:
• New AND (house OR (home NOT improvement NOT depot NOT grown))
• (+(buying purchasing -renting) +(home house residence –(+property -bedroom)))
3.1.5 查询一批文档。
对单元,短语,布尔查询有了基本的理解之后,我们现在可以深入内部看看solr怎么使用lucene的倒排索引匹配文档。回头看
表 3.5,其中的一部分转载到表3.6。
表3.6
的
Term Document (Continued)...
beginner’s 6 home 2,5,7,8
buy 9 house 6,9
buying 4,5,6 how 3,9
car 4 new 4,5,8
child 3 owner 8
cooking 1 purchasing 7
decorating 2 raise 3
first 9 the 6
fun 1 to 1,6,9
如果现在用户输入一个"new home".鉴于前面的倒排索引,如何能够找到匹配的文件,查询Solr。
答案是,查询new home是两个单词的的查询.
Term Document
home 2,5,7,8
new 4,5,8
一旦找到匹配文件列表中每个短语,Lucene进行集合运算得出一个合适的最终结果集。假定默认操作符是一个OR。就取两个结果集的并集。4,5,8 交集 2,5,7,8 等于 2,,4,5,7,8
如图3.3
如果查询条件是AND.结果返回交集 5,8 如图3.4
图3.4
除了交集和并集,否定集合也很常见,图3.5,演示了该项搜索查询的结果集的各种结果集
图3.5 常用布尔查询算法的图形表示
正如你所见,很强大,接下来我们会看到,solr也提供了查询短语的能力。
3.1.6短语查询,单元定位
早些时候我们看到,除了在lucene索引中查询单元,我们还可以查询短语,回顾前面,索引只包含个别单元,你可能会怀疑我们是否能查询整个短语。
简短的答案是:查询短语的每个单词,也就是单元也还在Solr索引中存储。如果 查询的new home 替换为 "new home"。一旦发现连在一起的文档集,一个solr的特性就可以解决这个问题。这个特性就是 单词定位(term positions),是在文档中的相对位置的可选的记录,表3.7演示文档如何匹配用一个包含单词定位的倒排索引。
Table 3.7 包含单词定位的倒排索引
Original document Lucene’s inverted index with term positions
Doc# Content field Term Document Term Term position
1 A Fun Guide to Cooking a 1 4 2 2
2 Decorating Your Home cooking 1
3 How to Raise a Child decorating 2
4 Buying a New Car your 4
5 Buying a New Home home
6 The Beginner’s Guide to Buying a House
7 Purchasing a Home
8 Becoming a New Home Owner
9 How to Buy Your First House
在表 3.7中你可以看到 如果你输入new AND home 可以查找到5 and 8。单词定位更近一步,告诉我们每一个词在哪里出现,表3.8显示一个简明版本的倒排索引,旨在仅集中在讨论的单词定位的交集 new and home
Table 3.8 简述单词定位的倒排索引
Term Document Term position
home 5 4(代表在标题的第几个位置)
8 4
new 5 3
8 3
在这个例子中,new这个字在位置3 ,而home这个字在位置4.当标题为Buying a New Home和 Becoming a New Home Owner的时候,这是有意义的,通过确保匹配项在彼此的一个位置出现,solr可以确保几个单词在初始文档中,是一个短语,比如 new 在 第五个和第八个文档中,new 的位置是3 正好在4前面。你现在明白单词定位(term positions)的意义了吧.它们允许您在其各自的文档中重建索引词的原始位置,使其能够在查询时搜索特定的短语.
寻找特定短语,不是term positions提供的唯一好处,我们将在下一节中看到他们使用的另一个很好的例子,来改进我们的搜索结果质量。
3.1.7。模糊匹配
Solr提供执行模糊匹配查询的几种类型的能力。模糊匹配是指在搜索索引中的单词进行不精确匹配。例如,有人可能想要搜索一个特定的前缀开头的单词。模糊匹配的能力,是一个功能强大的工具。