更新请求处理器
Solr 收到的每个更新请求都会通过一系列插件运行,这些插件称为更新请求处理器或URP。
例如,这对于向正在编入索引的文档添加字段、更改特定字段的值或在传入文档不满足特定条件时删除更新非常有用。事实上,Solr 中数量惊人的功能都是作为更新处理器实现的,因此有必要了解此类插件如何工作以及它们在哪里配置。
URP 解剖和生命周期
更新请求处理器作为 链 的一部分创建,该链包含一个或多个更新处理器。Solr 创建了一个默认更新请求处理器链,其中包括几个更新请求处理器,这些处理器启用了 Solr 的基本功能。除非用户选择配置和指定不同的自定义更新请求处理器链,否则此默认链用于处理每个更新请求。
描述更新请求处理器最简单的方法是查看抽象类 UpdateRequestProcessor 的 Javadoc。每个 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 如何配置为通过使用 name、features、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"/>
在这种情况下,配置了名为“signature”的 SignatureUpdateProcessorFactory
实例,并定义了名为“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 托管分片 1 的领导者,节点 B 托管分片 2 的领导者,节点 C 托管分片 2 的 NRT 类型副本。假设将更新请求发送到节点 A,该节点将更新转发到节点 B(因为更新属于分片 2),然后将更新分发到其副本节点 C。让我们看看每个节点上发生的情况
-
节点 A:通过
SignatureUpdateProcessor
(计算签名并将其放入“id”字段)运行更新,然后通过LogUpdateProcessor
,再通过DistributedUpdateProcessor
。此处理器确定更新实际上属于节点 B,并将其转发到节点 B。更新未进一步处理。这是必需的,因为下一个处理器RunUpdateProcessor
将针对本地分片 1 索引执行更新,这会导致分片 1 和分片 2 上的数据重复。 -
节点 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 "http://localhost: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 "http://localhost: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 "http://localhost: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
中的更新链中。强烈建议您查看这些类的 Javadoc;这些说明是摘自 Javadoc 的缩写片段。
通用更新处理器工厂
- AddSchemaFieldsUpdateProcessorFactory
-
如果输入文档包含一个或多个与模式中任何字段或动态字段不匹配的字段,此处理器将动态地将字段添加到模式中。
- AtomicUpdateProcessorFactory
-
此处理器将常规字段值文档转换为原子更新文档。此处理器可以在运行时使用(无需在
solrconfig.xml
中定义它),请参阅以下 AtomicUpdateProcessorFactory 部分。 - ClassificationUpdateProcessorFactory
-
此处理器使用 Lucene 的分类模块来提供简单的文档分类。有关如何使用此处理器的更多详细信息,请参阅 https://cwiki.apache.org/confluence/display/solr/SolrClassification。
- CloneFieldUpdateProcessorFactory
-
将任何匹配的源字段中的值克隆到配置的目标字段中。
- DefaultValueUpdateProcessorFactory
-
一个简单的处理器,它向任何尚未在 fieldName 中具有值的文档添加一个默认值。
- DocBasedVersionConstraintsProcessorFactory
-
此工厂生成一个 UpdateProcessor,它有助于使用 versionField 的配置名称基于每个文档的版本号来强制执行文档的版本约束。
- DocExpirationUpdateProcessorFactory
-
用于管理文档自动“过期”的更新处理器工厂。
- FieldNameMutatingUpdateProcessorFactory
-
通过使用配置的
replacement
替换与配置的pattern
的所有匹配项来修改字段名称。 - IgnoreCommitOptimizeUpdateProcessorFactory
-
允许您在 SolrCloud 模式下运行时忽略来自客户端应用程序的提交和/或优化请求,有关更多信息,请参阅:SolrCloud 中的分片和索引数据
- IgnoreLargeDocumentProcessorFactory
-
允许您防止大小超过
limit
(以 KB 为单位)的大型文档被索引。它有助于防止索引和恢复时因非常大的文档而导致的意外问题。默认情况下,如果此处理器遇到超出其配置限制的文档,它将中止更新请求并将错误发送回用户。在违规者之前处理的文档由 Solr 索引;违规者之后的文档保持未处理状态。
或者,处理器提供“宽容”模式(
permissiveMode=true
),该模式跳过违规文档并记录警告,但不会中止批处理的其余部分或向用户返回错误。 - RegexpBoostProcessorFactory
-
一个处理器,它将“inputField”的内容与“boostFilename”中找到的正则表达式进行匹配,如果匹配,它将从文件中返回相应的提升值,并以双精度值的形式将其输出到“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 javadoc,以了解它们在配置要修改的字段时支持的常见选项的详细信息。
- ConcatFieldUpdateProcessorFactory
-
使用可配置的分隔符连接与指定条件匹配的字段的多个值。
- CountFieldValuesUpdateProcessorFactory
-
使用该字段的值的数量替换与指定条件匹配的字段的任何值列表。
- FieldLengthUpdateProcessorFactory
-
使用这些 CharSequences 的长度(作为整数)替换与指定条件匹配的字段中找到的任何 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 执行更新命令。几乎所有处理器链都应以
RunUpdateProcessorFactory
的实例结束,除非用户明确地在备用自定义UpdateRequestProcessorFactory
中执行更新命令。
可在运行时使用的更新处理器
这些更新处理器不需要在 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 and
lastName
从文档字段中提供。如果其中任何一个字段缺失,则该部分将替换为空字符串。如果这些字段为多值,则仅使用第一个值。