Apache Solr 是广泛使用的搜索引擎。有几个著名的平台使用 Solr;Netflix 和 Instagram 是其中的一些名称。我们在 tajawal 的应用程序中一直使用 Solr 和 ElasticSearch。在这篇文章中,我将为您提供一些关于如何编写优化的 Schema 文件的技巧。我们不会讨论 Solr 的基础知识,我希望您了解它的工作原理。 虽然您可以在 Schema 文件中定义字段和一些默认值,但您不会获得必要的性能提升。您必须注意某些关键配置。在这篇文章中,我将讨论这些配置,您可以使用它们在性能方面充分利用 Solr。 事不宜迟,让我们开始了解这些配置是什么。
1.配置缓存
Solr 缓存与索引搜索器的特定实例相关联,索引的特定视图在该搜索器的生命周期内不会更改。 为了最大化性能,配置缓存是最重要的一步。 配置`filterCache`: 过滤器缓存由 SolrIndexSearcher 用于过滤器。过滤器缓存允许您控制过滤器查询的处理方式,以最大限度地提高性能。FilterCache 的主要好处是当打开一个新的搜索器时,它的缓存可以使用旧搜索器的缓存中的数据进行预填充或“自动预热”。所以它肯定有助于最大限度地提高性能。例如:
代码语言:javascript复制<filterCache
class="solr.FastLRUCache"
size="512"
initialSize="512"
autowarmCount="0"
/>
类:SolrCache 实现 LRUCache(LRUCache 或 FastLRUCache) size:缓存中的最大条目数 initialSize:缓存的初始容量(条目数)。(参见 java.util.HashMap) autowarmCount:要从旧缓存预填充的条目数。 配置`queryResultCache`和`documentCache`: queryResultCache 缓存保存先前搜索的结果:基于查询、排序和请求的文档范围的文档 ID 的有序列表 (DocList)。 documentCache 缓存保存 Lucene Document 对象(每个文档的存储字段)。由于 Lucene 内部文档 ID 是瞬态的,因此该缓存不会自动预热。 您可以根据您的应用程序配置它们。它在您主要使用只读用例的情况下提供更好的性能。 假设您有一个博客,一个博客可以在帖子上有帖子和评论。在 Post 的情况下,我们可以启用这些缓存,因为在这种情况下,数据库读取远远超过写入。所以在这种情况下,我们可以为 Posts 启用这些缓存。 例如:
代码语言:javascript复制<queryResultCache
class="solr.LRUCache"
size="512"
initialSize="512"
autowarmCount="0"
/><documentCache
class="solr.LRUCache"
size="512"
initialSize="512"
autowarmCount="0"
/>
如果您主要使用只写用例,请在每次软提交时禁用 queryResultCache 和 documentCache,这些缓存会被刷新,并且不会产生太大的性能影响。因此请记住上面提到的博客示例,我们可以在评论的情况下禁用这些缓存。
2.配置SolrCloud
如今,云计算非常流行,它允许您管理可扩展性、高可用性和容错性。Solr 能够设置结合容错和高可用性的 Solr 服务器集群。 在 setupSolrCloud 环境中,您可以配置“主”和“从”复制。使用“主”实例来索引信息,并使用多个从属(基于需求)来查询信息。在主服务器上的 solrconfig.xml 文件中,包括以下配置:
代码语言:javascript复制<str name="confFiles">
solrconfig_slave.xml:solrconfig.xml,x.xml,y.xml
</str>
查看 Solr Docs 了解更多详细信息。
3.配置`Commits`
为了使数据可用于搜索,我们必须将其提交到索引。在某些情况下,当您拥有数十亿条记录时,提交可能会很慢,Solr 使用不同的选项来控制提交时间,让您可以更好地控制何时提交数据,您必须根据您的应用程序选择选项。 “提交”或“软提交”: 您可以通过发送 commit=true 参数和更新请求来简单地将数据提交到索引,它将对所有 Lucene 索引文件进行硬提交到稳定存储,它将确保所有索引段都应该更新,并且成本可能很高当你有大数据时。 为了使数据立即可用于搜索,可以使用附加标志 softCommit=true,它会快速提交您对 Lucene 数据结构的更改但不保证将 Lucene 索引文件写入稳定存储,此实现称为Near Real Time,一项提高文档可见性的功能,因为您不必等待后台合并和存储(如果使用 SolrCloud,则为 ZooKeeper)完成,然后再进行其他操作。 自动提交: autoCommit 设置控制挂起更新自动推送到索引的频率。您可以设置时间限制或最大更新文档限制来触发此提交。也可以在发送更新请求时使用 `autoCommit` 参数定义。您还可以在 Request Handler 中定义如下:
代码语言:javascript复制<autoCommit>
<maxDocs>20000</maxDocs>
<maxTime>50000</maxTime>
<openSearcher>false</openSearcher>
</autoCommit>
maxDocs:自上次提交以来发生的更新数。 maxTime:自最旧的未提交更新以来的毫秒数 openSearcher:执行提交时是否打开一个新的搜索器。如果这是错误的,则提交会将最近的索引更改刷新到稳定存储,但不会导致打开新的搜索器以使这些更改可见。默认值为真。 在某些情况下,您可以完全禁用 autoCommit,例如,如果您将数百万条记录从不同的数据源迁移到 Solr,您不希望在每次插入时都提交数据,甚至不希望在批量的情况下提交数据。每 2、4 或 6 千次插入都不需要它,因为它仍然会减慢迁移速度。在这种情况下,您可以完全禁用 `autoCommit` 并在迁移结束时进行提交,或者您可以将其设置为较大的值,例如 3 小时(即 3*60*60*1000)。您还可以添加 <maxDocs>50000000</maxDocs>,这意味着仅在添加 5000 万个文档后才会自动提交。发布所有文档后,手动或从 SolrJ 调用一次 commit - 提交需要一段时间,但总体上会快得多。 此外,在您完成批量导入后,减少 maxTime 和 maxDocs,以便您对 Solr 所做的任何增量帖子都会更快地提交。
4.配置动态字段
Apache Solr 的一项惊人功能是 dynamicField。当您有数百个字段并且您不想定义所有字段时,它非常方便。 动态字段与常规字段一样,只是它的名称中带有通配符。在索引文档时,不匹配任何明确定义的字段的字段可以与动态字段匹配。 例如,假设您的架构包含一个名为 *_i 的动态字段。如果您尝试使用 cost_i 字段索引文档,但架构中没有明确定义 cost_i 字段,则 cost_i 字段将具有为 *_i 定义的字段类型和分析。 但是你在使用dynamicField时必须小心,不要广泛使用它,因为它也有一些缺点,如果你使用投影(如“abc.*.xyz.*.fieldname”)来获取特定的动态字段列,使用正则表达式解析字段需要时间。在返回查询结果的同时也增加了解析时间,下面是创建动态字段的示例。
代码语言:javascript复制<dynamicField
name="*.fieldname"
type="boolean"
multiValued="true"
stored="true"
/>
使用动态字段意味着您可以在字段名称中拥有无限数量的组合,因为您指定了通配符,有时可能会很昂贵,因为 Lucene 为每个唯一字段(列)名称分配内存,这意味着如果您有一行包含列A、B、C、D 和另一行有 E、F、C、D,Lucene 将分配 6 块内存而不是 4 块,因为有 6 个唯一列名,所以即使有 6 个唯一列名,万一百万行,它可能会使堆崩溃,因为它将使用 50% 的额外内存。
5. 配置索引与存储字段
索引字段意味着您正在使字段可搜索,indexed="true" 使字段可搜索、可排序和可分面,例如,如果您有一个名为 test1 且 indexed="true" 的字段,那么您可以像 q= 一样搜索它test1:foo,其中 foo 是您要搜索的值,因此,仅将搜索所需的那些字段设置为 indexed="true",如果需要,其余字段应为 indexed="false"在搜索结果中。例如:
代码语言:javascript复制<field name="foo" type="int" stored="true" indexed="false"/>
这意味着我们可以减少重新索引时间,因为在每次重新索引时,Solr 都会应用过滤器、标记器和分析器,这会增加一些处理时间,如果我们的索引数量较少的话。
6.配置复制字段
Solr 提供了非常好的功能,称为 copyField,它是一种将多个字段的副本存储到单个字段的机制。copyField 的使用取决于场景,但最常见的是创建单个“搜索”字段,当用户或客户端未指定要查询的字段时,该字段将用作默认查询字段。 对所有通用文本字段使用copyField并将它们复制到一个文本字段中,并使用它进行搜索,它会减少索引大小并为您提供更好的性能,例如,如果您有像ab_0_aa_1_abcd这样的动态数据,并且您想要复制所有 具有后缀 _abcd 到一个字段的字段。您可以在 schema.xml 中创建一个 copyField,如下所示:
代码语言:javascript复制<copyField source="*_abcd" dest="wxyz"/>
source:要复制的字段的名称 dest:复制字段的名称
7. 使用过滤查询‘fq’
在搜索中使用 Filter Query fq 参数对于最大化性能非常有用,它定义了一个查询,可用于限制可以返回的文档的超集,而不影响分数,它独立缓存查询。 Filter Queryfq 对于加速复杂查询非常有用,因为使用 fq 指定的查询独立于主查询进行缓存。当后面的查询使用相同的过滤器时,会发生缓存命中,并且过滤器结果会从缓存中快速返回。 下面是使用过滤器查询的 curl 示例:
代码语言:javascript复制POST
{
"form_params": {
"fq": "id=1234",
"fl": "abc cde",
"wt": "json"
},
"query": {
"q": "*:*"
}
}
过滤 qeury 参数也可以在单个搜索 qeury 中多次使用。查看 Solr Filter Qeury 文档以获取更多详细信息。
8. 使用构面查询
Apache Solr 中的 Faceting 用于将搜索结果分类为不同的类别,执行聚合操作(如按特定字段分组、计数、分组等)非常有帮助,因此,对于所有聚合特定查询,您可以使用 Facet 来 开箱即用地进行聚合,它也将成为性能提升器,因为它纯粹是为此类操作而设计的。 下面是向 solr 发送构面请求的 curl 示例。
代码语言:javascript复制{
"form_params": {
"fq" : "fieldName:value",
"fl" : "fieldName",
"facet" : "true",
"facet.mincount": 1,
"facet.limit" : -1,
"facet.field" : "fieldName",
"wt" : "json",
},
"query" : {
"q": "*:*",
},
}
fq:过滤查询 fl:结果中要返回的字段列表 facet:true/false 启用/禁用构面计数 facet.mincount:排除计数低于 1 的范围 facet.limit:限制结果中返回的组数,-1 表示全部 facet.field:该字段应被视为构面(对结果进行分组)
结论:
将 Solr 投入生产时,性能改进是关键步骤。Solr 中有许多调整旋钮可以帮助您最大限度地提高系统的性能,其中一些我们在本博客中讨论过,在 solr-config 文件中进行更改以使用最佳配置,使用适当的索引选项或字段更新架构文件 类型,尽可能使用过滤器 queriesfq 并使用适当的缓存选项,但这又取决于您的应用程序。 这就结束了。