更新请求处理器
Solr 收到的每个更新请求都会通过一系列称为更新请求处理器或 URP 的插件运行。
例如,这对于向正在编制索引的文档添加字段、更改特定字段的值或在传入文档不满足某些条件时删除更新非常有用。实际上,Solr 中大量功能都是作为更新处理器实现的,因此有必要了解此类插件的工作方式以及它们的配置位置。
URP 剖析和生命周期
更新请求处理器是作为一个或多个更新处理器的链的一部分创建的。Solr 创建一个默认更新请求处理器链,其中包含一些启用基本 Solr 功能的更新请求处理器。除非用户选择配置和指定不同的自定义更新请求处理器链,否则此默认链用于处理每个更新请求。
描述更新请求处理器的最简单方法是查看抽象类 UpdateRequestProcessor 的 Javadocs。每个 UpdateRequestProcessor 都必须有一个相应的工厂类,该类扩展 UpdateRequestProcessorFactory。此工厂类由 Solr 用于创建此插件的新实例。这种设计提供了两个好处
-
更新请求处理器不必是线程安全的,因为它只被一个请求线程使用,并且在请求完成后销毁。
-
工厂类可以接受配置参数并维护请求之间可能需要的任何状态。工厂类必须是线程安全的。
每个更新请求处理器链都在加载 Solr 核心期间构建并缓存,直到核心卸载。链中指定的每个 UpdateRequestProcessorFactory
也会被实例化并使用可能在 solrconfig.xml
中指定的配置进行初始化。
当 Solr 收到更新请求时,它会查找用于此请求的更新链。使用相应的工厂创建链中指定的每个 UpdateRequestProcessor 的新实例。更新请求被解析为相应的 UpdateCommand 对象,这些对象通过链运行。每个 UpdateRequestProcessor 实例负责调用链中的下一个插件。它可以通过不调用下一个处理器来选择短路链,甚至可以通过抛出异常来中止进一步的处理。
单个更新请求可能包含一批多个新文档或删除,因此对于每个单独的更新,将多次调用 UpdateRequestProcessor 的相应 processXXX 方法。但是,保证单个线程将串行调用这些方法。 |
更新请求处理器配置
可以通过直接在 solrconfig.xml
中创建整个链,或者在 solrconfig.xml
中创建单个更新处理器,然后通过请求参数指定所有处理器,在运行时动态创建链来创建更新请求处理器链。
但是,在我们了解如何配置更新处理器链之前,我们必须先了解默认更新处理器链,因为它提供了大多数自定义请求处理器链也需要的基本功能。
默认更新请求处理器链
如果在 solrconfig.xml
中没有配置任何更新处理器链,Solr 将自动创建一个默认的更新处理器链,用于所有更新请求。这个默认的更新处理器链由以下处理器组成(按顺序):
-
LogUpdateProcessorFactory
- 跟踪在此请求期间处理的命令并记录它们。 -
DistributedUpdateProcessorFactory
- 负责将更新请求分发到正确的节点,例如,将请求路由到正确分片的主节点,并将更新从主节点分发到每个副本。此处理器仅在 SolrCloud 模式下激活。 -
RunUpdateProcessorFactory
- 使用内部 Solr API 执行更新。
这些处理器都执行必要的功能,因此任何自定义链通常都包含所有这些处理器。 RunUpdateProcessorFactory
通常是任何自定义链中的最后一个更新处理器。
自定义更新请求处理器链
以下示例演示如何在 solrconfig.xml
中配置自定义链。
<updateRequestProcessorChain name="dedupe">
<processor class="solr.processor.SignatureUpdateProcessorFactory">
<bool name="enabled">true</bool>
<str name="signatureField">id</str>
<bool name="overwriteDupes">false</bool>
<str name="fields">name,features,cat</str>
<str name="signatureClass">solr.processor.Lookup3Signature</str>
</processor>
<processor class="solr.LogUpdateProcessorFactory" />
<processor class="solr.RunUpdateProcessorFactory" />
</updateRequestProcessorChain>
在上面的示例中,创建了一个名为“dedupe”的新更新处理器链,链中包含 SignatureUpdateProcessorFactory
、LogUpdateProcessorFactory
和 RunUpdateProcessorFactory
。 SignatureUpdateProcessorFactory
进一步配置了不同的参数,例如“signatureField”、“overwriteDupes”等。此链是如何配置 Solr 以通过计算使用名称、特征、cat 字段的值作为“id”字段的签名来执行文档去重的示例。您可能已经注意到,此链未指定 DistributedUpdateProcessorFactory
。由于此处理器对于 Solr 的正常运行至关重要,因此 Solr 会自动将 DistributedUpdateProcessorFactory
插入到任何不包含它的链中,紧接在 RunUpdateProcessorFactory
之前。
RunUpdateProcessorFactory
不要忘记在您在 |
将单个处理器配置为顶级插件
更新请求处理器也可以在 solrconfig.xml
中独立于链进行配置。
<updateProcessor class="solr.processor.SignatureUpdateProcessorFactory" name="signature">
<bool name="enabled">true</bool>
<str name="signatureField">id</str>
<bool name="overwriteDupes">false</bool>
<str name="fields">name,features,cat</str>
<str name="signatureClass">solr.processor.Lookup3Signature</str>
</updateProcessor>
<updateProcessor class="solr.RemoveBlankFieldUpdateProcessorFactory" name="remove_blanks"/>
在这种情况下,SignatureUpdateProcessorFactory
的实例被配置为名称“signature”,并且定义了名称为“remove_blanks”的 RemoveBlankFieldUpdateProcessorFactory
。在 solrconfig.xml
中指定以上内容后,我们可以在 solrconfig.xml
中的更新请求处理器链中引用它们,如下所示:
<updateProcessorChain name="custom" processor="remove_blanks,signature">
<processor class="solr.RunUpdateProcessorFactory" />
</updateProcessorChain>
SolrCloud 中的更新处理器
在用户管理的集群或单节点安装中,每个更新都会在链中运行所有更新处理器一次。然而,在 SolrCloud 中,更新请求处理器的行为值得特别考虑。
SolrCloud 的一项关键功能是请求的路由和分发。对于更新请求,此路由由 DistributedUpdateRequestProcessor
实现,并且由于其重要功能,此处理器在 Solr 中被赋予特殊地位。
在 SolrCloud 集群中,链中 DistributedUpdateProcessor
之前的所有处理器都在第一个接收来自客户端的更新的节点上运行,而无论此节点作为主节点还是副本。然后,DistributedUpdateProcessor
将更新转发到相应的分片主节点以进行更新(或者在影响多个文档的更新(例如,按查询删除或提交)的情况下,转发到多个主节点)。分片主节点使用事务日志应用 部分文档更新,然后将更新转发到所有分片副本。主节点和每个副本运行链中列出的 DistributedUpdateProcessor
之后的所有处理器。
例如,考虑我们在上面部分看到的“dedupe”链。假设存在一个 3 节点 SolrCloud 集群,其中节点 A 托管 shard1 的主节点,节点 B 托管 shard2 的主节点,节点 C 托管 shard2 的 NRT 类型副本。假设一个更新请求被发送到节点 A,该节点将更新转发到节点 B(因为更新属于 shard2),然后节点 B 将更新分发到其副本节点 C。让我们看看每个节点会发生什么:
-
节点 A:通过
SignatureUpdateProcessor
(计算签名并将其放入“id”字段),然后通过LogUpdateProcessor
,最后通过DistributedUpdateProcessor
运行更新。此处理器确定更新实际上属于节点 B,并转发到节点 B。更新不会进一步处理。这是必需的,因为下一个处理器RunUpdateProcessor
将针对本地 shard1 索引执行更新,这会导致 shard1 和 shard2 上出现重复数据。 -
节点 B:接收更新并看到它是由另一个节点转发的。更新直接发送到
DistributedUpdateProcessor
,因为它已经在节点 A 上通过了SignatureUpdateProcessor
,并且再次进行相同的签名计算将是冗余的。DistributedUpdateProcessor
确定更新确实属于此节点,将其分发到节点 C 上的副本,然后将更新进一步转发到链中的RunUpdateProcessor
。 -
节点 C:接收更新并看到它是由其主节点分发的。更新直接发送到
DistributedUpdateProcessor
,该处理器执行一些一致性检查并将更新进一步转发到链中的RunUpdateProcessor
。
总而言之:
-
DistributedUpdateProcessor
之前的所有处理器仅在接收更新请求的第一个节点上运行,无论它是转发节点(例如,上面的示例中的节点 A)还是主节点(例如,节点 B)。我们称这些为“预处理器”或仅称“处理器”。 -
DistributedUpdateProcessor
之后的所有处理器仅在主节点和副本节点上运行。它们不在转发节点上执行。这些处理器称为“后处理器”。
在上一节中,我们看到 updateRequestProcessorChain
配置为 processor="remove_blanks, signature"
。这意味着这些处理器是第 1 种,并且仅在转发节点上运行。类似地,我们可以通过使用“post-processor”属性指定它们为第 2 种,如下所示:
<updateProcessorChain name="custom" processor="signature" post-processor="remove_blanks">
<processor class="solr.RunUpdateProcessorFactory" />
</updateProcessorChain>
然而,仅在转发节点上执行处理器是一种通过负载均衡器随机发送请求来在 SolrCloud 集群中分发诸如去重之类的昂贵计算的好方法。否则,昂贵的计算将在主节点和副本节点上重复进行。
自定义更新链后处理器可能永远不会在恢复的副本上调用
|
原子更新处理器工厂
如果 AtomicUpdateProcessorFactory
在 DistributedUpdateProcessor
之前的更新链中,则传入链的文档将是部分文档。
由于 DistributedUpdateProcessor
负责在主节点上将 原子更新 处理为完整文档,这意味着仅在转发节点上执行的预处理器只能对部分文档进行操作。如果您有一个必须处理完整文档的处理器,那么唯一的选择是将其指定为后处理器。
使用自定义链
update.chain 请求参数
update.chain
参数可用于任何更新请求,以选择在 solrconfig.xml
中配置的自定义链。例如,为了选择前面部分中描述的“dedupe”链,可以发出以下请求:
curl "https://127.0.0.1:8983/solr/gettingstarted/update/json?update.chain=dedupe&commit=true" -H 'Content-type: application/json' -d '
[
{
"name" : "The Lightning Thief",
"features" : "This is just a test",
"cat" : ["book","hardcover"]
},
{
"name" : "The Lightning Thief",
"features" : "This is just a test",
"cat" : ["book","hardcover"]
}
]'
以上操作应删除两个相同的文档中的重复项,并且仅索引其中一个。
处理器和后处理器请求参数
我们可以使用 processor
和 post-processor
请求参数动态构造自定义更新请求处理器链。可以为这两个参数指定多个处理器,以逗号分隔的值形式。例如:
curl "https://127.0.0.1:8983/solr/gettingstarted/update/json?processor=remove_blanks,signature&commit=true" -H 'Content-type: application/json' -d '
[
{
"name" : "The Lightning Thief",
"features" : "This is just a test",
"cat" : ["book","hardcover"]
},
{
"name" : "The Lightning Thief",
"features" : "This is just a test",
"cat" : ["book","hardcover"]
}
]'
curl "https://127.0.0.1:8983/solr/gettingstarted/update/json?processor=remove_blanks&post-processor=signature&commit=true" -H 'Content-type: application/json' -d '
[
{
"name" : "The Lightning Thief",
"features" : "This is just a test",
"cat" : ["book","hardcover"]
},
{
"name" : "The Lightning Thief",
"features" : "This is just a test",
"cat" : ["book","hardcover"]
}
]'
在第一个示例中,Solr 将动态创建一个链,该链具有“signature”和“remove_blanks”作为预处理器,仅在转发节点上执行,而在第二个示例中,“remove_blanks”将作为预处理器执行,“signature”将在主节点和副本上作为后处理器执行。
将自定义链配置为默认链
我们还可以指定一个自定义链作为发送到特定更新处理程序的所有请求的默认值,而不是在每个请求的请求参数中指定名称。
可以通过为给定的路径添加“update.chain”或“processor”和“post-processor”作为默认参数来实现此目的,这可以通过 InitParams 或在所有请求处理程序都支持的 “defaults”部分中添加它们来完成。
以下是在 无模式模式 中定义的 initParam
,它将自定义更新链应用于所有以“/update/”开头的请求处理程序。
<initParams path="/update/**">
<lst name="defaults">
<str name="update.chain">add-unknown-fields-to-the-schema</str>
</lst>
</initParams>
或者,可以使用如下示例中所示的“defaults”来实现类似的效果:
<requestHandler name="/update/extract" startup="lazy" class="solr.extraction.ExtractingRequestHandler" >
<lst name="defaults">
<str name="update.chain">add-unknown-fields-to-the-schema</str>
</lst>
</requestHandler>
更新请求处理器工厂
接下来是对当前可用的更新请求处理器进行的简要说明。如有必要,可以将 UpdateRequestProcessorFactory
集成到 solrconfig.xml
中的更新链中。强烈建议您检查这些类的 Javadocs;这些描述是主要从 Javadocs 中提取的简短摘要。
通用 UpdateProcessorFactories
- AddSchemaFieldsUpdateProcessorFactory
-
如果输入文档包含一个或多个与模式中的任何字段或动态字段不匹配的字段,则此处理器将动态地将字段添加到模式中。
- AtomicUpdateProcessorFactory
-
此处理器会将传统的字段值文档转换为原子更新文档。此处理器可以在运行时使用(无需在
solrconfig.xml
中定义它),请参阅下面的 AtomicUpdateProcessorFactory 部分。 - ClassificationUpdateProcessorFactory
-
此处理器使用 Lucene 的分类模块来提供简单的文档分类。有关如何使用此处理器的更多详细信息,请参阅 https://cwiki.apache.org/confluence/display/solr/SolrClassification。
- CloneFieldUpdateProcessorFactory
-
将任何匹配的源字段中找到的值克隆到配置的目标字段中。
- DefaultValueUpdateProcessorFactory
-
一个简单的处理器,将默认值添加到任何在 fieldName 中尚无值的文档中。
- DocBasedVersionConstraintsProcessorFactory
-
此工厂生成一个 UpdateProcessor,该处理器有助于根据使用已配置的版本字段名称的每个文档的版本号来强制执行对文档的版本约束。
- DocExpirationUpdateProcessorFactory
-
用于管理文档自动“过期”的更新处理器工厂。
- FieldNameMutatingUpdateProcessorFactory
-
通过将所有与配置的
pattern
匹配的项替换为配置的replacement
来修改字段名称。 - IgnoreCommitOptimizeUpdateProcessorFactory
-
允许您在 SolrCloud 模式下运行时忽略来自客户端应用程序的提交和/或优化请求,有关更多信息,请参阅:SolrCloud 中的分片和索引数据
- IgnoreLargeDocumentProcessorFactory
-
允许您阻止大小超过
limit
(以 KB 为单位) 的大型文档被索引。这有助于防止因非常大的文档而导致的索引和恢复方面的意外问题。默认情况下,如果此处理器遇到超出其配置限制的文档,它将中止更新请求并将错误返回给用户。违规文档之前处理的文档会被 Solr 索引;违规文档之后的文档将保持未处理状态。
或者,该处理器提供一种“允许”模式 (
permissiveMode=true
),它会跳过违规文档并记录警告,但不会中止剩余的批处理或向用户返回错误。 - NumFieldLimitingUpdateRequestProcessorFactory
-
一旦核心超出可配置的“最大”字段数,就会导致更新请求失败。
如果核心累积了太多字段(例如,超过 500 个),Solr 的性能可能会下降甚至变得不稳定。“NumFieldLimiting” URP 作为一种安全措施,帮助用户在这些性能和稳定性问题出现之前,注意到潜在的危险模式设计和/或动态字段的误用。请注意,索引报告的字段计数可能会受到已删除(但尚未清除)的文档的影响,并且可能因副本而异。为了避免副本之间的这种差异,在 SolrCloud 模式下运行时,此 URP 几乎总是应该在 DistributedUpdateProcessor 之前使用。
- RegexpBoostProcessorFactory
-
一个处理器,它将 "inputField" 的内容与 "boostFilename" 中找到的正则表达式进行匹配,如果匹配,将从文件中返回相应的 boost 值,并将其作为双精度值输出到 "boostField"。
- SignatureUpdateProcessorFactory
-
使用一组定义的字段为文档生成哈希“签名”。对于仅索引“相似”文档的一个副本很有用。
- ScriptUpdateProcessorFactory
-
一个处理器,它允许使用作为脚本实现的更新处理器。请在 脚本更新处理器部分了解更多信息。
- TemplateUpdateProcessorFactory
-
允许根据模板模式向文档添加新字段。此更新处理器也可以在运行时使用(无需在
solrconfig.xml
中定义),请参阅下面的 TemplateUpdateProcessorFactory 部分。 - TimestampUpdateProcessorFactory
-
一个更新处理器,它将新生成的“NOW”日期值添加到任何正在添加的、指定字段中尚无值的文档。
- URLClassifyProcessorFactory
-
更新处理器,它检查 URL 并将该 URL 的特征输出到各种其他字段,包括长度、路径级别数、是否为顶级 URL(级别 == 0)、是否看起来像登录/索引页面、URL 的规范表示形式(例如,剥离 index.html)、URL 的域名和路径部分等。
- UUIDUpdateProcessorFactory
-
一个更新处理器,它将新生成的 UUID 值添加到任何正在添加的、指定字段中尚无值的文档。此处理器也可以在运行时使用(无需在
solrconfig.xml
中定义),请参阅下面的 UUIDUpdateProcessorFactory 部分。
FieldMutatingUpdateProcessorFactory 派生的工厂
这些工厂都提供在索引文档时修改文档中字段的功能。使用这些工厂中的任何一个时,请查阅 FieldMutatingUpdateProcessorFactory javadocs,了解它们都支持配置要修改哪些字段的通用选项的详细信息。
- ConcatFieldUpdateProcessorFactory
-
使用可配置的分隔符连接匹配指定条件的字段的多个值。
- CountFieldValuesUpdateProcessorFactory
-
将匹配指定条件的字段的任何值列表替换为该字段的值的计数。
- FieldLengthUpdateProcessorFactory
-
将匹配指定条件的字段中找到的任何 CharSequence 值替换为这些 CharSequence 的长度(作为整数)。
- FirstFieldValueUpdateProcessorFactory
-
仅保留匹配指定条件的字段的第一个值。
- HTMLStripFieldUpdateProcessorFactory
-
删除匹配指定条件的字段中找到的任何 CharSequence 值中的所有 HTML 标记。
- IgnoreFieldUpdateProcessorFactory
-
忽略并删除添加到索引的任何文档中匹配指定条件的字段。
- LastFieldValueUpdateProcessorFactory
-
仅保留匹配指定条件的字段的最后一个值。
- MaxFieldValueUpdateProcessorFactory
-
一个更新处理器,它仅保留在找到多个值的情况下,任何选定字段的最大值。
- MinFieldValueUpdateProcessorFactory
-
一个更新处理器,它仅保留在找到多个值的情况下,任何选定字段的最小值。
- ParseBooleanFieldUpdateProcessorFactory
-
尝试将选定的仅具有 CharSequence 类型值的字段转换为布尔值。
- ParseDateFieldUpdateProcessorFactory
-
尝试将选定的仅具有 CharSequence 类型值的字段转换为日期值。
- ParseNumericFieldUpdateProcessorFactory 派生的类
-
- ParseDoubleFieldUpdateProcessorFactory
-
尝试将选定的仅具有 CharSequence 类型值的字段转换为双精度值。
- ParseFloatFieldUpdateProcessorFactory
-
尝试将选定的仅具有 CharSequence 类型值的字段转换为浮点值。
- ParseIntFieldUpdateProcessorFactory
-
尝试将选定的仅具有 CharSequence 类型值的字段转换为整数值。
- ParseLongFieldUpdateProcessorFactory
-
尝试将选定的仅具有 CharSequence 类型值的字段转换为长整型值。
- PreAnalyzedUpdateProcessorFactory
-
一个更新处理器,它使用配置的格式解析器,使用 PreAnalyzedField 解析任何正在添加的文档的配置字段。
- RegexReplaceProcessorFactory
-
一个更新的处理器,它将配置的正则表达式应用于选定字段中找到的任何 CharSequence 值,并将任何匹配项替换为配置的替换字符串。
- RemoveBlankFieldUpdateProcessorFactory
-
删除找到的任何长度为 0 的 CharSequence 值(即,空字符串)。
- TrimFieldUpdateProcessorFactory
-
从匹配指定条件的字段中找到的任何 CharSequence 值中删除前导和尾随空格。
- TruncateFieldUpdateProcessorFactory
-
将匹配指定条件的字段中找到的任何 CharSequence 值截断为最大字符长度。
- UniqFieldsUpdateProcessorFactory
-
删除匹配指定条件的字段中找到的重复值。
可以作为插件加载的更新处理器工厂
这些处理器作为“模块”包含在 Solr 版本中,需要在运行时加载额外的 jar 包。有关详细信息,请参阅与每个模块关联的 README 文件
langid
模块提供-
- LangDetectLanguageIdentifierUpdateProcessorFactory
-
使用 http://code.google.com/p/language-detection 识别一组输入字段的语言。
- TikaLanguageIdentifierUpdateProcessorFactory
-
使用 Tika 的 LanguageIdentifier 识别一组输入字段的语言。
analysis-extras
模块提供-
- OpenNLPExtractNamedEntitiesUpdateProcessorFactory
-
使用 OpenNLP NER 模型提取的命名实体更新要索引的文档。请注意,要在 SolrCloud 上使用大于 1MB 的模型文件,您必须配置 ZooKeeper 服务器和客户端,或者将模型文件存储在托管集合副本的每个节点的文件系统上。
您不应修改或删除的更新处理器工厂
这些是为了完整起见而列出的,但它们是 Solr 基础架构的一部分,特别是 SolrCloud。除了确保在修改更新请求处理程序(或您进行的任何副本)时不删除它们之外,您很少需要更改这些。
- DistributedUpdateProcessorFactory
-
用于将更新分发到所有必要的节点。
- NoOpDistributingUpdateProcessorFactory
-
DistributingUpdateProcessorFactory
的替代 No-Op 实现,它始终返回 null。专为想要绕过分布式更新并使用自己的自定义更新逻辑的专家设计。
- LogUpdateProcessorFactory
-
一个日志记录处理器。它跟踪已通过链的所有命令,并在 finish() 时打印它们。
- RunUpdateProcessorFactory
-
使用底层 UpdateHandler 执行更新命令。除非用户在替代自定义
UpdateRequestProcessorFactory
中显式执行更新命令,否则几乎所有处理器链都应以RunUpdateProcessorFactory
的实例结尾。
可以在运行时使用的更新处理器
这些更新处理器不需要在 solrconfig.xml
中进行任何配置。当它们的名称添加到随更新请求发送的 processor
参数时,它们会自动初始化。可以通过附加多个以逗号分隔的处理器名称来使用多个处理器。
AtomicUpdateProcessorFactory
AtomicUpdateProcessorFactory
用于原子地更新文档。
使用参数 processor=atomic
来调用它。使用它将您的普通 update
操作转换为原子更新操作。当您使用 /update/csv
或 /update/json/docs
等端点时,这尤其有用,这些端点没有原子操作的语法。
例如
processor=atomic&atomic.field1=add&atomic.field2=set&atomic.field3=inc&atomic.field4=remove&atomic.field4=remove
以上参数按以下方式转换正常的 update
操作
-
field1
到原子add
操作 -
field2
到原子set
操作 -
field3
到原子inc
操作 -
field4
到原子remove
操作
TemplateUpdateProcessorFactory
TemplateUpdateProcessorFactory
可用于根据模板模式向文档添加新字段。
使用参数 processor=template
来使用它。模板参数 template.field
(多值)定义要添加的字段和模式。模板可能包含引用文档中其他字段的占位符。您可以在单个请求中包含多个 Template.field
参数。
例如
processor=template&template.field=fullName:Mr. {firstName} {lastName}
上面的示例将向文档添加一个名为 fullName
的新字段。字段 firstName
和 lastName
从文档字段提供。如果其中任何一个缺失,则该部分将替换为空字符串。如果这些字段是多值的,则仅使用第一个值。