在意识到需要一个由工程师组成的文字团队才能使我们的自我管理的Solr基础设施保持最新并正常工作后,我们正在转向一个托管搜索解决方案——Elasticsearch!
更具体地说,我们正在迁移到Elasticsearch,它由Amazon Web Services(AWS)托管和管理。这两个搜索引擎有很多相似之处,但确实需要一些术语、模式和思维的翻译。
超过2021,我们已经将一个较小的搜索索引完全迁移到弹性搜索,并且目前正在使用弹性搜索来搜索一些新的搜索域。迄今为止的旅程教会了我们很多Solr和Elastic之间的关键区别,以及人们可能不知道的细微差别,除非他们经历了类似的迁移。
我们把这篇博文放在一起是为了帮助其他正在考虑这样一个练习的人。
我们从2014年开始在Canva使用Solr,当时它是最活跃的社区中最成熟的选择。现在,在2022年,Elasticsearch不再是一个乏味且有点不可靠的新手,而是已经证明自己是一个可靠的搜索引擎,拥有强大的开发者社区和支持。
现在,雇佣具有Elasticsearch经验的工程师变得更容易了,雇佣熟悉Solr的人也更难了。
以下各节并排比较了我们如何体验Solr和Elasticsearch,我们对它们的喜爱和挣扎,以及我们希望在迁移之前了解Elasticsearch的情况。我们希望这将有利于希望做同样事情的团队。
我们(作为工程师)与技术互动的关键区别在于基础设施的管理方式。以下是要考虑的方面。
必须单独管理以解决问题。如果你在管理Solr,你还必须管理Zookeeper。
自动缩放可以添加节点以保持最小复制,但不支持在AZs(AWS可用性区域)之间进行平衡。
自动缩放不会平衡副本以防止危险的拓扑。我们观察到自动缩放的几种不良行为。
两个节点被指定为同一碎片的副本,如果其中一个崩溃,会给幸存者带来巨大的负载,通常还会导致幸存者死亡。
将多个节点作为副本添加到单个领导者,同时导致领导者尝试将其数据同时分发给两个新的追随者。这偶尔会让领导倒台。
我们有一些自我管理的脚本,以确保碎片的副本位于不同的节点中并跨AZ,但这不是现成的。
碎片根据复制值放置在节点上,复制值在索引创建时定义,或由索引模板指定。
solrconfig。xml,其中包含一些设置,例如自定义默认手持器、zookeeper超时和自动提交间隔。
可以使用具有这些设置默认值的索引模板创建索引,但更改模板不会更改活动索引的配置。要更改活动索引的配置,必须直接将设置或映射应用于该索引。
Elasticsearch处理索引配置的方式与Solr相比有很大变化。了解什么是索引模板以及如何使用它们有助于将Solr配置文件转换为Elasticsearch上下文。
索引模板包含定义索引的设置和映射。它们指定一个索引模式(例如test-*),该模式应用于与该模式匹配的所有新索引。
映射定义字段以及它们应该使用的分析器/标记器。映射也可以标记为";动态";:"严格的";,这要求您显式地添加要为映射编制索引的字段(就像Solr中的大多数字段一样);如果要编制索引的文档包含映射中未定义的字段,则无法编制索引。
还可以使用组件模板创建索引模板。例如,不同的组件模板可能各自定义:
然后,可以使用这三个模板创建索引模板,将它们的组合配置应用于新索引。
Elasticsearch和Solr具有类似的标记化器和分析器,但对模式的定义不同,并且有自己的索引行为。
<;字段名=";品牌";类型=";简单的文字";索引=";正确";存储=";假";必需=";假";多值=";正确"/>&书信电报;字段类型名称=";简单的文字";等级=";索尔。文本字段和#34;位置增量差距=";100">&书信电报;分析仪>&书信电报;标记器类=";索尔。WhitespaceTokenizerFactory"/>&书信电报;过滤等级=";索尔。小写字母filterFactory"/>&书信电报;过滤等级=";索尔。ASCIIFoldingFilterFactory"/></分析仪></fieldType>;
{";设置";:{";简单文本";{";标记器";:";标准";";过滤器";[";小写";";"映射";:{";动态";:";严格";";属性";:{";品牌";{";类型";:";文本";}
要求字段由字段名显式定义,或作为动态字段定义,例如title-*。
对于大多数查询,Solr和Elasticsearch之间有直接等价物,但通常具有不同的标签和查询结构;
获取/搜索{";查询";{";布尔";{";必须";[{";匹配";{";头衔";:&";搜索";},{";匹配";:{";内容";:";弹性搜索";}]"过滤器";:[{";任期";:{";状态";:";出版";},{";范围";:{";出版日期";:{";gte";:";2015-01-01";}
获取/搜索{";#源";:{";包括";:[";名称";";id";]"查询";:{";术语";:{";用户";:";kimchy";}
Elasticsearch支持将对象字段映射为嵌套数据类型。以这种方式映射的对象捕获结构化数据,可以单独查询,也可以作为字段集合查询。
放置my-index-000001{";映射";{";属性";{";用户";{";类型";";嵌套";属性";{";第一&&";#类型&&";#"最后";:{";类型";:";文本";}"第34组:{";类型";:";关键字";}}}
把my-index-000001/#u doc/1{";组";";粉丝";";用户";[{";第一";";约翰&";";最后";&,{";第一";";爱丽丝";";最后";";怀特";}
//匹配具有匹配//first或last of"的任何用户对象的文档;罗伯特";获取my-index-000001/#u search{";query";{";bool";{";must";:[{";match";user.&&";&&";Robert";}}匹配具有单个用户对象的文档,这些对象匹配//first of";简"**和**第34项中的最后一项;史密斯和#34;获取my-index-000001/#u search{";query";{";bool";{";must";:[{";match";user.first";Jane";},{";匹配";:{";用户。最后";:";史密斯";}}}
我们向Elasticsearch的迁移解锁了一些向量搜索选项,通过将向量编码为二进制doc_值,可以将字段映射为密集和稀疏向量。值得注意的是,lucene(以及Elasticsearch和Solr)正在这一领域添加功能,包括Solr最近对HNSW向量搜索的支持。
维护文档和API参考,以及活跃的在线社区。尽管我们非常感谢Solr和Zookeeper的Apache邮件列表,但拥有在线论坛是一种胜利。
如果您想要一个非结构化搜索,可以将任何内容放入索引中,那么动态字段是很好的选择,但是如果您想要一个有保证字段的结构化搜索,那么必须在索引之前设置它。
Elasticsearch无法指定所有文档都需要一个给定的字段,或者一个给定的字段必须只有一个值,因为您需要一个带有故障处理器的摄取管道。
这似乎是一件小事(而且可能是),但从Solr的角度来看。xml模式到Elasticsearch';在JSON模板中,您必须为所有有见地的注释找到一个新的家,比如我们不想使用小写用户名的原因。
另一件小事情,但来自Solr,在Solr中很容易获得一个图,并查看哪些节点在哪个碎片上以及它们的当前状态,Elasticsearch需要一种不同的思维方式来调试。例如,如果Elasticsearch集群为黄色,则必须在没有漂亮图片的情况下调试它。
抽象的奇妙之处使infra超级容易设置,这使得确定哪些节点或实例出现故障变得更加困难。幸运的是,我们已经成功地用节点和索引的度量设置了仪表板,以便能够发现异常值。
您可以将额外的文件(例如包含同义词的文件)上载到集合,并按id引用它们。但是,此id是在上载时设置的,不可更改或指定。
这些是从我们的第一个搜索引擎迁移到Elasticsearch框架中吸取的经验教训。我们现在正在努力将我们规模更大、设置更完善的服务,以及它们整整7年的模式,转变为Elasticsearch!
从最初的迁移开始,我们很高兴不需要设置一个带有仔细记录设置的动物园管理员。我们也感谢移民之旅教会我们的所有知识。
围绕我们迁移的另一个大问题是Elasticsearch和OpenSearch产品的发展和差异。我们目前使用的是Elasticsearch 7.10,能够追踪任何一个流,并将继续关注他们各自的搜索功能和托管选项。
Brandon Janson,Nic Laver,Yiwei Han,Stuart Cam:他在我们的搜索平台上工作,迁移关键的搜索组件。