使用更新处理器进行索引

更新处理器是设计用于向索引添加、删除和更新文档的请求处理器。除了具有用于导入富文档的插件(请参阅 使用 Solr Cell 和 Apache Tika 进行索引)之外,Solr 原生支持索引 XML、CSV 和 JSON 中的结构化文档。

配置和使用请求处理器的推荐方法是使用基于路径的名称,这些名称映射到请求 URL 中的路径。但是,如果 requestDispatcher 配置正确,也可以使用 qt(查询类型)参数指定请求处理器。可以使用多个名称访问同一处理器,如果您希望指定不同的默认选项集,这可能会很有用。

单个统一更新请求处理器支持 XML、CSV、JSON 和 javabin 更新请求,根据 ContentStreamContent-Type 委托给适当的 ContentStreamLoader

如果您需要在加载文档之后但在索引之前(甚至在对照模式检查之前)对文档进行预处理,Solr 为更新请求处理器提供了文档预处理插件,称为 更新请求处理器,它允许默认和自定义配置链。

UpdateRequestHandler 配置

默认配置文件默认配置了更新请求处理器。

<requestHandler name="/update" class="solr.UpdateRequestHandler" />

XML 格式的索引更新

可以使用 Content-type: application/xmlContent-type: text/xml 将索引更新命令作为 XML 消息发送到更新处理器。

添加文档

更新处理器识别的用于添加文档的 XML 模式非常简单

  • <add> 元素引入要添加的一个或多个文档。

  • <doc> 元素引入构成文档的字段。

  • <field> 元素呈现特定字段的内容。

例如

<add>
  <doc>
    <field name="authors">Patrick Eagar</field>
    <field name="subject">Sports</field>
    <field name="dd">796.35</field>
    <field name="numpages">128</field>
    <field name="desc"></field>
    <field name="price">12.40</field>
    <field name="title">Summer of the all-rounder: Test and championship cricket in England 1982</field>
    <field name="isbn">0002166313</field>
    <field name="yearpub">1982</field>
    <field name="publisher">Collins</field>
  </doc>
  <doc>
  ...
  </doc>
</add>

添加命令支持一些可选的属性,可以指定这些属性。

commitWithin

可选

默认值:无

在指定的毫秒数内添加文档。

overwrite

可选

默认值:true

指示是否应检查唯一键约束以覆盖同一文档的先前版本(见下文)。

如果文档模式定义了唯一键,则默认情况下,对文档执行 /update 操作将覆盖(即替换)索引中具有相同唯一键的任何文档。 如果没有定义唯一键,则索引性能会稍微快一些,因为无需检查是否有现有文档需要替换。

如果您有唯一键字段,但您确信可以安全地绕过唯一性检查(例如,您批量构建索引,并且您的索引代码保证永远不会多次添加同一文档),则在添加文档时可以指定 overwrite="false" 选项。

XML 更新命令

更新期间的提交和优化

<commit> 操作将自上次提交以来加载的所有文档写入磁盘上的一个或多个段文件。在发出提交之前,新索引的内容对搜索不可见。提交操作会打开一个新的搜索器,并触发已配置的任何事件侦听器。

可以使用 <commit/> 消息显式发出提交,也可以通过 solrconfig.xml 中的 <autocommit> 参数触发。

<optimize> 操作请求 Solr 合并内部数据结构。对于大型索引,优化需要一些时间才能完成,但是通过将许多小的段文件合并为更大的段,可以提高搜索性能。如果您使用 Solr 的复制机制在许多系统之间分发搜索,请注意,优化后,需要传输完整的索引。

您应该仅考虑在静态索引上使用优化,即可以作为常规更新过程的一部分进行优化的索引(例如,每日更新一次)。需要 NRT 功能的应用程序不应使用优化。

<commit><optimize> 元素接受以下可选属性

waitSearcher

可选

默认值:true

阻塞直到新的搜索器被打开并注册为主要查询搜索器,使更改可见。

expungeDeletes

可选

默认值:false

合并具有超过 10% 已删除文档的段,在此过程中清除已删除的文档。生成的段将遵守 maxMergedSegmentMB。此选项仅适用于 <commit> 操作。

expungeDeletes 的开销比优化小,但同样的警告也适用。
maxSegments

可选

默认值:无

尽力将段合并到不超过此数量的段,但不保证实现该目标。除非有明显的证据表明优化到少量段是有益的,否则应省略此参数并接受默认行为。此选项仅适用于 <optimize 操作。默认为无限制,生成的段遵守 maxMergedSegmentMB 设置。

以下是使用可选属性的 <commit><optimize> 的示例

<commit waitSearcher="false"/>
<commit waitSearcher="false" expungeDeletes="true"/>
<optimize waitSearcher="false"/>

删除操作

可以通过两种方式从索引中删除文档。“按 ID 删除”删除具有指定 ID 的文档,并且仅当在模式中定义了 UniqueID 字段时才可以使用。它不适用于子文档/嵌套文档。“按查询删除”删除与指定查询匹配的所有文档,尽管 commitWithin 对按查询删除将被忽略。单个删除消息可以包含多个删除操作。

<delete>
  <id>0002166313</id>
  <id>0031745983</id>
  <query>subject:sport</query>
  <query>publisher:penguin</query>
</delete>

在按查询删除中使用 Join 查询解析器时,应使用值为 "none" 的 score 参数,以避免 ClassCastException。有关 score 参数的更多详细信息,请参阅 Join 查询解析器 部分。

回滚操作

回滚命令回滚自上次提交以来对索引所做的所有添加和删除操作。它既不调用任何事件侦听器,也不创建新的搜索器。其语法很简单:<rollback/>

分组操作

您可以通过使用周围的 <update> 元素对多个命令进行分组,从而在单个 XML 文件中发布它们。

<update>
  <add>
    <doc><!-- doc 1 content --></doc>
  </add>
  <add>
    <doc><!-- doc 2 content --></doc>
  </add>
  <delete>
    <id>0002166313</id>
  </delete>
</update>

使用 curl 执行更新

您可以使用 curl 实用程序执行上述任何命令,使用其 --data-binary 选项将 XML 消息附加到 curl 命令,并生成 HTTP POST 请求。例如

curl https://127.0.0.1:8983/solr/my_collection/update -H "Content-Type: text/xml" --data-binary '
<add>
  <doc>
    <field name="authors">Patrick Eagar</field>
    <field name="subject">Sports</field>
    <field name="dd">796.35</field>
    <field name="isbn">0002166313</field>
    <field name="yearpub">1982</field>
    <field name="publisher">Collins</field>
  </doc>
</add>'

对于发布文件中包含的 XML 消息,可以使用另一种形式

curl https://127.0.0.1:8983/solr/my_collection/update -H "Content-Type: text/xml" --data-binary @myfile.xml

上面的方法效果很好,但是使用 --data-binary 选项会导致 curl 在将其发布到服务器之前将整个 myfile.xml 加载到内存中。在处理多 GB 文件时,这可能会有问题。此替代的 curl 命令执行等效操作,但 curl 内存使用量最少

curl https://127.0.0.1:8983/solr/my_collection/update -H "Content-Type: text/xml" -T "myfile.xml" -X POST

如果 solrconfig.xmlrequestParsers 元素中启用了 HTTP GET 命令,则也可以使用该命令发送简短的请求,URL 编码请求,如下所示。请注意 "<" 和 ">" 的转义

curl https://127.0.0.1:8983/solr/my_collection/update?stream.body=%3Ccommit/%3E&wt=xml

来自 Solr 的响应采用此处所示的形式

<response>
  <lst name="responseHeader">
    <int name="status">0</int>
    <int name="QTime">127</int>
  </lst>
</response>

如果失败,状态字段将为非零。

使用 XSLT 转换 XML 索引更新

脚本模块 提供了一个单独的 XSLT 更新请求处理程序,允许您通过使用 <tr> 参数应用 XSL 转换 来索引任何任意 XML。您必须在 configsetconf/xslt 目录中有一个 XSLT 样式表,该样式表可以将传入的数据转换为预期的 <add><doc/></add> 格式,并使用 tr 参数指定该样式表的名称。

您需要在使用此功能之前启用 脚本模块

tr 参数

XSLT 更新请求处理程序接受 tr 参数,该参数标识要使用的 XML 转换。必须在 Solr conf/xslt 目录中找到该转换。

XSLT 配置

以下示例来自 Solr 发行版中的 sample_techproducts_configs configset,展示了如何配置 XSLT 更新请求处理程序。

<!--
  Changes to XSLT transforms are taken into account
  every xsltCacheLifetimeSeconds at most.
-->
<requestHandler name="/update/xslt"
                     class="solr.scripting.xslt.XSLTUpdateRequestHandler">
  <int name="xsltCacheLifetimeSeconds">5</int>
</requestHandler>

xsltCacheLifetimeSeconds 的值为 5 对于开发来说很好,可以快速查看 XSLT 更改。对于生产环境,您可能需要更高的值。

XSLT 更新示例

这是 sample_techproducts_configs/conf/xslt/updateXml.xsl XSL 文件,用于将标准 Solr XML 输出转换为 Solr 预期的 <add><doc/></add> 格式

<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
  <xsl:output media-type="text/xml" method="xml" indent="yes"/>
  <xsl:template match='/'>
    <add>
      <xsl:apply-templates select="response/result/doc"/>
    </add>
  </xsl:template>
  <!-- Ignore score (makes no sense to index) -->
  <xsl:template match="doc/*[@name='score']" priority="100"></xsl:template>
  <xsl:template match="doc">
    <xsl:variable name="pos" select="position()"/>
    <doc>
      <xsl:apply-templates>
        <xsl:with-param name="pos"><xsl:value-of select="$pos"/></xsl:with-param>
      </xsl:apply-templates>
    </doc>
  </xsl:template>
  <!-- Flatten arrays to duplicate field lines -->
  <xsl:template match="doc/arr" priority="100">
    <xsl:variable name="fn" select="@name"/>
    <xsl:for-each select="*">
      <xsl:element name="field">
        <xsl:attribute name="name"><xsl:value-of select="$fn"/></xsl:attribute>
        <xsl:value-of select="."/>
      </xsl:element>
    </xsl:for-each>
  </xsl:template>
  <xsl:template match="doc/*">
    <xsl:variable name="fn" select="@name"/>
      <xsl:element name="field">
        <xsl:attribute name="name"><xsl:value-of select="$fn"/></xsl:attribute>
      <xsl:value-of select="."/>
    </xsl:element>
  </xsl:template>
  <xsl:template match="*"/>
</xsl:stylesheet>

此样式表将 Solr 的 XML 搜索结果格式转换为 Solr 的更新 XML 语法。一个示例用法是将 Solr 1.3 索引(没有 CSV 响应写入器)复制为可以索引到另一个 Solr 文件中的格式(前提是所有字段都已存储)

$ curl -o standard_solr_xml_format.xml "https://127.0.0.1:8983/solr/techproducts/select?q=ipod&fl=id,cat,name,popularity,price,score&wt=xml"

$ curl -X POST -H "Content-Type: text/xml" -d @standard_solr_xml_format.xml "https://127.0.0.1:8983/solr/techproducts/update/xslt?commit=true&tr=updateXml.xsl"
您可以使用 响应写入器 XSLT 示例中的 tr 参数查看相反的导出/导入周期。

JSON 格式的索引更新

Solr 可以接受符合定义的结构的 JSON,也可以接受任意 JSON 格式的文档。如果发送任意格式的 JSON,则需要在更新请求中发送一些额外的参数,这些参数在 转换和索引自定义 JSON 部分中进行了描述。

Solr 风格的 JSON

可以使用 Content-Type: application/jsonContent-Type: text/json 将 JSON 格式的更新请求发送到 Solr 的 /update 处理程序。

JSON 格式的更新可以采用 3 种基本形式,如下文深入描述

  • 单个文档,表示为顶级 JSON 对象。为了将其与一组命令区分开,需要 json.command=false 请求参数。

  • 文档列表,表示为包含每个文档的 JSON 对象的顶级 JSON 数组。

  • 一系列更新命令,表示为顶级 JSON 对象(Map)。

添加单个 JSON 文档

通过 JSON 添加文档的最简单方法是使用 /update/json/docs 路径将每个文档单独作为 JSON 对象发送

curl -X POST -H 'Content-Type: application/json' 'https://127.0.0.1:8983/solr/my_collection/update/json/docs' --data-binary '
{
  "id": "1",
  "title": "Doc 1"
}'

添加多个 JSON 文档

可以通过 JSON 对象数组一次添加多个文档,其中每个对象代表一个文档

curl -X POST -H 'Content-Type: application/json' 'https://127.0.0.1:8983/solr/my_collection/update' --data-binary '
[
  {
    "id": "1",
    "title": "Doc 1"
  },
  {
    "id": "2",
    "title": "Doc 2"
  }
]'

example/exampledocs/books.json 中提供了一个示例 JSON 文件,其中包含您可以添加到 Solr “techproducts” 示例中的对象数组

curl 'https://127.0.0.1:8983/solr/techproducts/update?commit=true' --data-binary @example/exampledocs/books.json -H 'Content-type:application/json'

发送 JSON 更新命令

通常,JSON 更新语法通过简单的映射支持 XML 更新处理程序支持的所有更新命令。一个消息中可以包含多个命令,包括添加和删除文档

curl -X POST -H 'Content-Type: application/json' 'https://127.0.0.1:8983/solr/my_collection/update' --data-binary '
{
  "add": {
    "doc": {
      "id": "DOC1",
      "my_field": 2.3,
      "my_multivalued_field": [ "aaa", "bbb" ]   (1)
    }
  },
  "add": {
    "commitWithin": 5000, (2)
    "overwrite": false,  (3)
    "doc": {
      "f1": "v1", (4)
      "f1": "v2"
    }
  },

  "commit": {},
  "optimize": { "waitSearcher":false },

  "delete": { "id":"ID" },  (5)
  "delete": { "query":"QUERY" } (6)
}'
1 可以为多值字段使用数组
2 在 5 秒内提交此文档
3 不要检查具有相同 uniqueKey 的现有文档
4 可以为多值字段使用重复的键
5 按 ID 删除(uniqueKey 字段)
6 按查询删除

与其他更新处理程序一样,可以在 URL 中而不是消息主体中指定诸如 commitcommitWithinoptimizeoverwrite 之类的参数。

JSON 更新格式允许简单的按 ID 删除。delete 的值可以是包含要删除的零个或多个特定文档 ID(不是范围)的列表的数组。例如,单个文档

{ "delete":"myid" }

或文档 ID 列表

{ "delete":["id1","id2"] }

注意:按 ID 删除不适用于子文档/嵌套文档。

您还可以在每个“delete”中指定 _version_

{
  "delete":"id":50,
  "_version_":12345
}

您还可以在更新请求的主体中指定删除的版本。

JSON 更新便捷路径

除了 /update 处理程序之外,默认情况下,Solr 中还有一些其他特定于 JSON 的请求处理程序路径可用,这些路径会隐式覆盖某些请求参数的行为

路径 默认参数

/update/json

stream.contentType=application/json

/update/json/docs

stream.contentType=application/json

json.command=false

对于那些在应用程序中设置 Content-Type 比较困难,但又想发送 JSON 格式更新命令的客户端,可以使用 /update/json 路径。而对于那些总是想发送文档(无论是单个文档还是列表),而无需担心完整 JSON 命令语法的客户端,/update/json/docs 路径可能特别方便。

自定义 JSON 文档

Solr 支持自定义 JSON。这部分内容在 转换和索引自定义 JSON 章节中进行了介绍。

CSV 格式的索引更新

可以使用 Content-Type: application/csvContent-Type: text/csv 将 CSV 格式的更新请求发送到 Solr 的 /update 处理程序。

example/exampledocs/books.csv 中提供了一个示例 CSV 文件,您可以使用它向 Solr 的 "techproducts" 示例中添加一些文档。

curl 'https://127.0.0.1:8983/solr/my_collection/update?commit=true' --data-binary @example/exampledocs/books.csv -H 'Content-type:application/csv'

CSV 更新参数

CSV 处理程序允许在 URL 中以以下形式指定多个参数:f.parameter.optional_fieldname=value

下表描述了更新处理程序的参数。

separator

可选

默认值:,

用作字段分隔符的字符。此参数是全局的;对于每个字段的使用,请参阅 split 参数。

示例:separator=%09

trim

可选

默认值:false

如果为 true,则删除值的前导和尾随空格。此参数可以是全局的,也可以是每个字段的。

示例:f.isbn.trim=truetrim=false

header

可选

默认值:true

如果输入的第一行包含字段名称,则设置为 true。如果缺少 fieldnames 参数,将使用这些字段名称。此参数是全局的。

fieldnames

可选

默认值:无

添加文档时要使用的字段名称的逗号分隔列表。此参数是全局的。

示例:fieldnames=isbn,price,title

literal.field_name

可选

默认值:无

指定字段名称的字面值。此参数是全局的。

示例:literal.color=red

skip

可选

默认值:无

要跳过的字段名称的逗号分隔列表。此参数是全局的。

示例:skip=uninteresting,shoesize

skipLines

可选

默认值:0

在 CSV 数据开始之前,要丢弃输入流中的行数,包括标题(如果存在)。此参数是全局的。

示例:skipLines=5

encapsulator

可选

默认值:无

可选地用于包围值的字符,以保留诸如 CSV 分隔符或空格之类的字符。此标准 CSV 格式通过将封装符加倍来处理在封装值中出现的封装符本身。

此参数是全局的;对于每个字段的使用,请参阅 split

示例:encapsulator="

escape

可选

默认值:无

用于转义 CSV 分隔符或其他保留字符的字符。如果指定了转义符,则除非也明确指定,否则不使用封装符,因为大多数格式使用封装或转义,而不是两者都使用。

示例:escape=\

keepEmpty

可选

默认值:false

保留并索引零长度(空)字段。此参数可以是全局的,也可以是每个字段的。

示例:f.price.keepEmpty=true

map

可选

默认值:无

将一个值映射到另一个值。格式为 map=value:replacement(可以为空)。此参数可以是全局的,也可以是每个字段的。

示例:map=left:rightf.subject.map=history:bunk

split

可选

默认值:无

如果为 true,则通过单独的解析器将字段拆分为多个值。此参数在每个字段的基础上使用,例如 f.FIELD_NAME_GOES_HERE.split=true

overwrite

可选

默认值:true

如果为 true,则基于 Solr 架构中声明的 uniqueKey 字段检查并覆盖重复的文档。如果您知道您正在索引的文档不包含任何重复项,那么将此项设置为 false 可能会大大加快速度。

此参数是全局的。

commit

可选

默认值:无

在数据摄取后发出提交。此参数是全局的。

commitWithin

可选

默认值:无

在指定的毫秒数内添加文档。此参数是全局的。

示例:commitWithin=10000

rowid

可选

默认值:无

rowid(行号)映射到由参数值指定的字段,例如,如果您的 CSV 没有唯一的键,并且您想将行 ID 用作唯一键。此参数是全局的。

示例:rowid=id

rowidOffset

可选

默认值:0

在将 rowid 添加到文档之前,将给定的偏移量(作为整数)添加到 rowid。此参数是全局的。

示例:rowidOffset=10

索引制表符分隔文件

用于索引 CSV 文档的相同功能也可以轻松用于索引制表符分隔文件(TSV 文件),甚至可以处理反斜杠转义而不是 CSV 封装。

例如,可以使用以下命令将 MySQL 表转储到制表符分隔的文件中:

SELECT * INTO OUTFILE '/tmp/result.txt' FROM mytable;

然后,可以通过将 separator 设置为制表符 (%09),并将 escape 设置为反斜杠 (%5c) 将此文件导入到 Solr 中。

curl 'https://127.0.0.1:8983/solr/my_collection/update/csv?commit=true&separator=%09&escape=%5c' --data-binary @/tmp/result.txt

CSV 更新便捷路径

除了 /update 处理程序之外,Solr 中默认还提供一个额外的 CSV 特定请求处理程序路径,该路径隐式覆盖某些请求参数的行为

路径 默认参数

/update/csv

stream.contentType=application/csv

对于那些在应用程序中设置 Content-Type 比较困难,但又想发送 CSV 格式更新命令的客户端,可以使用 /update/csv 路径。