白话基本对话

白话基本对话,第1张

白话IT之聊聊搜索

文/朱筠

Square是一家了不起的技术驱动型公司。这家公司的文化非常独特。就工程师文化而言,早期的广场在技术上还是比较大胆激进的。

为什么这么说?举几个例子。虽然Square的核心产品是刷卡器,但是Square尝试开发的产品真的很多,虽然不是每个产品都存活了很久。如电子商务平台、电子钱包、工资单系统等等。另外,Square早期有一批书呆子式的技术人员,包括Rails的贡献者,JavaGuice的发明者等等。而且Square从来不用新技术,比如ElasticSearch,Kafka等。版本不稳定的时候,Square已经用在产品上了。而且因为我们是自己的数据中心,所以不用亚马逊。所有支持服务,包括部署和生产的工具和环境,以及所有系统都是内部构建的。以上可能都和我们创始人Jack的技术背景有关。

虽然这些对于一个公司的发展来说不一定都是好事,但是对于工程师来说却是一个极好的成长环境。第一,有机会接触新技术或者技术前沿。其次,因为不断做新产品,在早期,几乎每一个项目从头到尾都是完全由两三个人来完成的。

我在Square做过两个大项目。一个是和前谷歌员工Ken一起建立Square的搜索后端。另一个是和Eric一起做SquareStore,一个电商平台,主要处理所有Square软硬件销售的支付流程。

虽然后来走上了付费的道路,但当时做搜索一年左右的经历还是挺有意思的。所以想整理一下,分享给大家。当然,一年的经验还远远没有体会到,所以可能说的话是入不了行家的眼的,所以这篇文章叫“白话”。

基本概念

说白了,搜索就是从现有的数据和信息中找到一些符合用户条件的匹配。

以最简单的数据库为例。完成用户对数据库的搜索无非是以下几个概念:数据存储格式,即tableschema新数据的写入查询到表;它还包括索引,以优化某些查询模式的性能;此外,您可以根据某个列的值对查询结果进行排序。

搜索引擎在基本概念上非常相似。比如ApacheSolr和Elasticsearch(以下简称ES)都是基于Lucene的,核心功能都差不多。(Lucene实际上是一个搜索引擎库,有一堆Jar文件和一个LuceneAPI接口。)因为直接使用LuceneAPI相对灵活,但使用它需要更多的工程工作,所以Solr或es被用在许多地方,这两者都基于一个在Lucene上添加了许多可用特性的包。

索引

Solr和ES的模式也可以看作是定义了数据的存储格式和结构。这样,当您有新数据要存储在可搜索的数据集中时,您需要将原始数据转换成Solr和ES文档定义的数据格式。这个过程通常被称为索引,或ETL。ETL是提取-转换-加载的缩写。在实践中,很多情况下,搜索数据源来自多个系统或服务,并且格式和数据结构不同。Extract是从这些不同的数据源中分析相关的字段和值,可能在某种程度上检查数据。传输是将提取的数据信息转换成搜索引擎的文档存储格式。一些数据可以被组合或聚集,或者可以进行一些转换或计算。最后,经过处理的文档可以以API可接受的格式加载到搜索引擎的文档中。

虽然ETL的流程说起来简单,就是搭建一个数据管道,但是实际 *** 作中有很多细节需要考虑和实现。以Extract为例。如何从数据源获取数据?作为数据源,服务可能会实时发布一些数据更新。此时,需要一些类似Trigger或FeedPublisher的机制来确保这样的数据更新能够被搜索引擎捕获。常见的方式有三种。第一,通过添加触发器,API调用;当数据改变时直接触发;一个是饲料模式;一种是像卡夫卡一样使用日志机制。后两者可以通过拉或推的方式触发索引。

这是关于实时索引。在搜索中,由于各种原因(比如早期ES的重分片),往往需要从0开始重新索引所有数据。这样,所有数据源都需要某种持久机制来存储所有数据更改的历史。完全重新索引,可以通过ETL从这些持久化的数据中重新生成搜索引擎文档。

转换主要是数据转换,通常比较简单。加载,也就是API调用,通常是一种固定的处理方式。然而,许多系统需要考虑负载、一致性和可伸缩性,因此从基础架构的角度来看,还需要进行某些调整,以确保向搜索后端实时无误地加载数据。

查询

其实查询最重要的两个概念,我觉得是匹配和评分。匹配就是找到所有符合查询条件的数据。评分就是制定一个规则,根据申请的要求对结果进行排序。

匹配的过程有时被称为分析的过程。通常的方法是标记加过滤。令牌化就是将数据划分成不可分割的小单元,然后通过对这些小单元的组合和筛选,找到所有适合需求的数据。

常见的评分也有两种,一种是搜索前的静态评分,即与查询无关,数据的不同字段预先设定一个权重。一个是搜索后得分,通常与查询的具体内容有关。不同的评分机制可以相互结合使用。但是,如何调整评分函数,使期望的搜索结果出现在列表的顶部,是很多产品的搜索和开发中需要做的事情。很多时候使用机器学习等方法来帮助调整评分函数的参数。

性能和可伸缩性

除了上面提到的两个最基本的功能:索引和查询,随着实际应用中数据的不断增加和查询的复杂性,对性能和可扩展性的要求往往也在不断提高。

不同的搜索引擎如Solr和es将提供不同的机制来定制不同的查询。分布式搜索等两种可伸缩性方法也是不同的。一些对灵活性或性能要求较高的地方,往往会基于底层Lucene定制自己的搜索系统,不考虑Solr或es。以下部分将进一步阐述这一讨论。

Solr和ElasticSearch的比较

历史背景

Solr在2004年就出来了,但一开始只是一个公司的内部项目。其源代码于2006年公开发布,2007年应用于部分高流量网站。2008年1.3版本的发布增加了一些分布式搜索功能,比如分片。但是在功能和特性上有很多限制。2010年,ES出来了。早期的ES在各种搜索功能、社区、品牌、成熟度上都远远落后于Solr。但由于它是为分布式搜索而设计的,并且迅速吸引了众多用户,不断迭代,很快成为Solr在该领域的有力对手。虽然Solr在2012年发布了SolrCloud,为分布式搜索提供了更好的支持,但首先ES已经在市场上站稳了脚跟,其次ES从那时起就在设计上致力于解决分布式搜索,所以很多需要分布式搜索的地方仍然成为首选。

主要区别

很多人都比较过这两者。例如,http://solr-vs-elasticsearch.com从API、基础设施、索引、搜索、可定制性等方面详细阐述了它们的优缺点。总的来说,两者的当前版本对大多数人需要的性能都有很好的支持。没说哪个更好。只是在一些小的特征上有所不同,比如es的渗透和Solr的枢轴面等。下面是几个大的区别(这些区别在以后的版本中似乎逐渐不那么明显)。

一个是集群中每个节点的管理。我在之前的文章“从ElasticSearch到ZooKeeperin白话IT”中提到过一些。ES的节点管理系统存在裂脑问题。SolrCloud使用ZooKeeper管理节点,解决了这个问题,但这意味着SolrCloud需要部署ZooKeeper。但由于ES实际上可以使用外部的ZooKeeper,而不是其内置的节点管理,所以这种差异并不那么明显。

第二,重新分片。我三年前用过Solr和ES。当时,他们都不能动态地改变碎片的数量。每次改变Shard的数量,你都要擦除所有的索引数据,重新做索引(从头ETL所有数据)。所以我们最初设计系统的时候,对Shard的配置非常谨慎。但是2013年以后,Solr就可以支持分片了。所以从这个角度来说,ES有一定的局限性。但是ES也支持Shard的再平衡,Solr不支持。总之,如果在一开始设计系统的时候就知道两者的局限性,或者重新索引搜索整个系统数据的成本不是太大,那么重新分片和分片再平衡问题不大。

第三,社区支持,即遇到疑难杂症时能否快速找到解决方案。三年前,Solr比ES成熟多了。当时ES遇到的很多问题很难找到详细的解释,但现在看来两者的用户群体都比较成熟,没有明显的区别。另外,因为Solr是完全开源的,ES允许任何用户投稿,但是只有ES的人可以审核批准合并。所以可能会有更多的开发者熟悉Solr。

此外,还有一些详细的对比。我觉得这篇文章写得很好,推荐阅读:

Solr还是elasticsearch——就是这个问题:https://www.datanami.com/2015/01/22/Solr-elasticsearch-Question/

个人感受

我在Square的时候,Solr和ES其实都用过。一开始Sqaure的搜索后端是用Solr写的,和Ruby结合在一起。当时Solr的一些定制,比如Schema,是一个Repo,它的ETL在另一个Repo里。后来在Hackathon,我和几个同事花了一周时间用当时刚火起来的es重新写了一个搜索原型,好玩。(当然只有一些基本的功能,没有设置数据管道,所以我们黑了一些数据。通过这个简单的原型,我们展示了es的一些优势,所以后来我们把整个搜索后端搬到了ES,让它成为一个独立的Java服务。

那么我们从Solr转到es的时候有什么优势呢?

一种是嵌套类型。什么意思?比如你需要索引一些类似淘宝上店铺的信息,同时你也需要索引一些类似商品的信息。其实这两个数据之间存在着类似父子的关系。ES对此有很好的支持。这样,在索引的ETL中,可以很自然地描述两个数据之间的关系(商品属于某个商店),在查询时,也可以很方便地编写需要过滤父类或子类的查询。当时我们搜索后需要这样一个功能。尽管有一种方法可以解决Solr问题,但是代码相对难以理解和维护。

第二,语法。Solr和Ruby结合,很多程序可以写得很小很灵活。ES的纯JSON表达略显臃肿。但是就像Ruby和Java的区别一样,这个JSON表达式更加一致,所有的代码都会有非常相似的结构,也更容易理解。另外,Solr从一开始就是为文本搜索而设计的。ES似乎对非文本数据有更好的支持。此外,由于其相对一致的语法规范,对于复杂的查询组合,ES语句的读写应该更简单、更清晰。

还有其他因素与公司当时的基础设施有关。

第一,前面说了,我们的Solr和ETL当时在两个Repo里。这样,每一次部署都需要两次回购部署的协调。并且所有代码变更的兼容性管理稍微复杂一些。而ES,和我们的ETL一起,实现了一个独立的Java服务。代码管理和部署相对简单。

二、数据管道的建立。当时公司里Kafka的生产者和消费者对Java的支持比较好,所以新的基于ES的搜索系统可以很容易的从Kafka获取数据。Solr+Ruby的老系统只能用比较老的触发器和Feed来获取数据。这样一来,ES对于很多上游数据管道的建立就干净多了,也漂亮多了。

第三,性能。当时使用的是ES的分布式支持,而旧的Solr系统实际上是单节点多副本架构。自然,ES在查询性能上要好得多。

搜索和推荐

很多时候,搜索系统和推荐系统可以共享一些后端服务。因为他们可以使用相同的索引数据,也就是说,他们只需要建立一个数据管道和ETL系统。在此基础上,可以通过不同的方式实现查询,从而实现搜索或推荐的功能。ESSOLR和ESSOLR都提供了类似的不同API。我们当时做了搜索后端,然后另一个项目组用我们的数据做了一个基于一些复杂的机器学习模型的推荐系统。在我们的搜索部分,只使用了一些基本的过滤和评分机制。

定制搜索系统

虽然使用原有的Lucene更具挑战性,但许多公司在一开始就选择构建自己的搜索后端(如Airbnb)。也有一些公司使用Solr或es一段时间,然后转向开发自己的搜索引擎。定制的主要原因是灵活性。

ES和Solr都是Lucene上的一层封装。这层封装就像很多按钮和组件一样,根据用户的设计给用户提供了一层新的API,方便你的很多需求和 *** 作。而且这层包装肯定也隐藏了一些底层功能。如果公司的应用程序与他们设计的(想象的)用例大相径庭,那么用这样的包来代替就很尴尬了。所以特殊的应用,往往是Solr或者ES提供的那些基本的搜索功能和API都不好用。另一个相关因素是性能。即使使用ES和Solr,写出所需的搜索函数也很笨拙,只是整个过程变得不那么直接,反而拐了个弯去调用Lucene的基本函数,性能必然会大打折扣。

但是搜索的定制需要更多的人力和时间,以及精通搜索的技术人员。所以还是有很多人直接用Solr或者ES。即使在这类拥有定制搜索系统的公司,一些新产品在推出初期也可能会选择Solr或es。

这里写的只是个人观点。如果有更多的人对这个话题感兴趣,可以在搜索中找到更多的资深朋友,以后再写。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/zz/764034.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-01
下一篇 2022-05-01

发表评论

登录后才能评论

评论列表(0条)

保存