标记器处理器

标记器请求处理程序,又名“SolrTextTagger”,是一个“文本标记器”。

给定一个具有类似名称字段的字典(Solr 索引),您可以将文本发布到此请求处理程序,它将返回每个出现的名称,其中包含偏移量和其他所需的文档元数据。它用于命名实体识别 (NER)。

标记器不进行任何自然语言处理 (NLP)(Lucene 文本分析除外),因此它被认为是“朴素的标记器”,但它绝对可以直接使用,并且可以使用它作为关键组件构建更完整的 NER 或 ERD(实体识别和消除歧义)系统。SolrTextTagger 也可以用于查询以进行查询理解或大型文档。

要了解如何使用它,请跳转到下面的教程

标记器请求处理程序尚不支持分片索引。它可以在以 SolrCloud 模式运行的集群中使用,但存储标记字典的集合必须是单分片集合。尽管有此限制,但可以支持数千万到数亿个名称(文档);最大值主要受内存限制。

标记器配置

要配置标记器,您的 Solr 模式需要 2 个字段

  • 唯一的键字段(有关如何在模式中定义唯一键,请参阅唯一键)。推荐的字段设置:设置 docValues=true

  • 标记字段,它必须是 TextField,索引链的末尾(而不是查询链)带有 ConcatenateGraphFilterFactory:在该过滤器上设置 preservePositionIncrements=false。推荐的字段设置:omitNorms=trueomitTermFreqAndPositions=true 并且可能指定帖子格式 — 请参阅性能提示

文本字段的索引分析链,除了需要在末尾使用 ConcatenateGraphFilterFactory 之外,还可以具有适合您的匹配首选项的任何分词器和过滤器。它可以有多词同义词,并使用 WordDelimiterGraphFilterFactory 例如。但是,请不要使用 FlattenGraphFilterFactory,因为它会干扰 ConcatenateGraphFilterFactory。位置间隙(例如,停用词)将被忽略;(目前)不支持使间隙变得重要。

另一方面,文本字段的查询分析链则更受限制。同一位置不应存在标记,因此不存在同义词扩展 — 请改为在索引时执行此操作。支持停用词(或任何其他引入位置间隙的过滤器)。在运行时,可以将标记器配置为将其视为标记中断或忽略它。

您的 solrconfig.xml 需要定义 solr.TagRequestHandler,它像搜索处理程序一样支持 defaultsinvariantsappends 部分。

有关配置示例,请跳转到下面的教程

标记器参数

可以使用请求参数完全配置标记器的执行。只需要 field

field

必需

默认值:无

用作字典的标记字段。这是必需的;您可能会在请求处理程序中指定它。

fq

可选

默认值:无

您可以指定一些过滤器查询来限制用于标记的字典。此参数与 solr.SearchHandler 使用的参数相同。

rows

可选

默认值:10000

要返回的最大文档数。此参数与 solr.SearchHandler 使用的参数相同。

fl

可选

默认值:无

Solr 用于列出要返回字段的标准参数。此参数与 solr.SearchHandler 使用的参数相同。

overlaps

可选

默认值:NO_SUB

选择用于确定重叠集合中哪些标签应该保留,哪些应该被修剪的算法。选项有:

  • ALL:发出所有标签。

  • NO_SUB:不发出完全包含在另一个标签内的标签(即,没有子标签)。

  • LONGEST_DOMINANT_RIGHT:给定一个重叠标签的集群,发出最长的标签(按字符长度)。如果长度相同,则选择最右边的标签。删除与此标签重叠的任何标签,然后重复该算法以查找可能在该集群中发出的其他标签。

matchText

可选

默认值:false

如果为 true,则在标签响应中返回匹配的文本。这将触发标签器在标记之前完全缓冲输入。

tagsLimit

可选

默认值:1000

响应中返回的最大标签数量。在此点之后,标记将有效地停止。

skipAltTokens

可选

默认值:false

如果为 true,则抑制可能发生的错误,例如,如果您在分析器中启用查询时的同义词扩展(通常不应该这样做)。除非您知道无法避免此类标记,否则请将其默认为 false

ignoreStopwords

可选

默认值:false

一个布尔标志,使停用词(或任何导致位置跳过的条件,如 >255 个字符的单词)被忽略,就像它们不存在一样。否则,其行为是将它们视为标记中的中断,假设您的索引文本分析配置没有定义 StopWordFilter。默认情况下,将检查索引分析链中是否存在 StopWordFilter,如果找到,则当未指定时 ignoreStopWords 为 true。您可能不应该配置 StopWordFilter,并且可能也不需要设置此参数。

xmlOffsetAdjust

可选

默认值:false

如果为 true,则表示输入是 XML,并且返回标签的偏移量应根据需要进行调整,以允许客户端在标签偏移量对处插入开始和结束元素。如果无法执行此操作,则将省略该标签。当使用此选项时,您应该在 schema 中配置 HTMLStripCharFilterFactory。这将触发标签器在标记之前完全缓冲输入。

Solr 用于控制响应格式的参数也受支持,例如 echoParamswtindent 等。

使用 Geonames 的教程

这是一个演示如何使用流行的 Geonames 数据集配置和使用文本标签器的教程。它不仅仅是一个教程;它是一个包含上述未描述信息的指南。

创建和配置 Solr 集合

创建一个名为 "geonames" 的 Solr 集合。在本教程中,我们假设使用默认的 "data-driven" 配置。它非常适合实验和快速入门,但不适合生产或优化。

bin/solr create -c geonames

配置标签器

我们需要首先配置 schema。"data driven" 模式允许我们将此步骤保持在最低限度 - 我们只需要声明一个字段类型、2 个字段和一个复制字段。

最关键的部分是预先定义 “tag” 字段类型。有很多方法可以配置文本分析;我们在这里不讨论这些选择。但重要的一点是索引分析器链末尾的 ConcatenateGraphFilterFactory。另一个重要的性能要素是 postingsFormat=FST50,它产生一个紧凑的基于 FST 的内存数据结构,这对于文本标签器尤其有利。

Schema 配置

curl -X POST -H 'Content-type:application/json'  https://127.0.0.1:8983/solr/geonames/schema -d '{
  "add-field-type":{
    "name":"tag",
    "class":"solr.TextField",
    "postingsFormat":"FST50",
    "omitNorms":true,
    "omitTermFreqAndPositions":true,
    "indexAnalyzer":{
      "tokenizer":{
         "class":"solr.StandardTokenizerFactory" },
      "filters":[
        {"class":"solr.EnglishPossessiveFilterFactory"},
        {"class":"solr.ASCIIFoldingFilterFactory"},
        {"class":"solr.LowerCaseFilterFactory"},
        {"class":"solr.ConcatenateGraphFilterFactory", "preservePositionIncrements":false }
      ]},
    "queryAnalyzer":{
      "tokenizer":{
         "class":"solr.StandardTokenizerFactory" },
      "filters":[
        {"class":"solr.EnglishPossessiveFilterFactory"},
        {"class":"solr.ASCIIFoldingFilterFactory"},
        {"class":"solr.LowerCaseFilterFactory"}
      ]}
    },

  "add-field":{"name":"name", "type":"text_general"},

  "add-field":{"name":"name_tag", "type":"tag", "stored":false },

  "add-copy-field":{"source":"name", "dest":["name_tag"]}
}'

配置自定义 Solr 请求处理程序

curl -X POST -H 'Content-type:application/json' https://127.0.0.1:8983/solr/geonames/config -d '{
  "add-requesthandler" : {
    "name": "/tag",
    "class":"solr.TaggerRequestHandler",
    "defaults":{"field":"name_tag"}
  }
}'

加载一些示例数据

我们将使用 CSV 格式的 Geonames.org 数据。Solr 可以非常灵活地加载各种格式的数据。这个 cities1000.zip 应该是一个大约 7MB 的文件,解压后会得到一个大约 22.2MB 的 cities1000.txt 文件,其中包含 145k 行,每一行代表世界上至少有 1000 人口的城市。

使用 bin/solr post

$ bin/solr post -c geonames -t text/csv \
  --params 'optimize=true&maxSegments=1&separator=%09&encapsulator=%00&fieldnames=id,name,,alternative_names,latitude,longitude,,,countrycode,,,,,,population,elevation,,timezone,lastupdate' \
  /tmp/cities1000.txt

或使用 curl

$ curl -X POST --data-binary @/path/to/cities1000.txt -H 'Content-type:application/csv' \
  'https://127.0.0.1:8983/solr/geonames/update?commit=true&optimize=true&maxSegments=1&separator=%09&encapsulator=%00&fieldnames=id,name,,alternative_names,latitude,longitude,,,countrycode,,,,,,population,elevation,,timezone,lastupdate'

这可能需要大约 35 秒;这取决于情况。如果 schema 仅针对我们真正需要的内容进行调整(如果不需要文本搜索,则不需要),则速度会快得多。

在该命令中,我们使用了 optimize=true&maxSegments=1 将索引置于一种可以加快标记速度的状态。encapsulator=%00 是一种禁用默认双引号的小技巧。

标记时间!

这是一个标记一小段文本的简单示例。有关更多选项,请参阅前面的文档。

$ curl -X POST \
  'https://127.0.0.1:8983/solr/geonames/tag?overlaps=NO_SUB&tagsLimit=5000&fl=id,name,countrycode&wt=json&indent=on' \
  -H 'Content-Type:text/plain' -d 'Hello New York City'

响应应该是这样的(QTime 可能有所不同)

{
  "responseHeader":{
    "status":0,
    "QTime":1},
  "tagsCount":1,
  "tags":[{
      "startOffset":6,
      "endOffset":19,
      "ids":["5128581"]}],
  "response":{"numFound":1,"start":0,"docs":[
      {
        "id":"5128581",
        "name":["New York City"],
        "countrycode":["US"]}]
  }}

标签器性能提示

  • 请遵循上述建议的配置字段设置。此外,为了获得最佳标签器性能,请设置 postingsFormat=FST50。但是,非默认的 postings 格式没有向后兼容性保证,因此,如果您升级 Solr,则可能会在启动时发现一个令人讨厌的异常,因为它无法读取旧索引。如果要标记的输入文本很小(例如,您正在标记查询或推文),则 postings 格式的选择并不那么重要。

  • 在将字典加载到一个 Lucene 段后,或者至少尽可能少地加载到段后,进行 "优化"。

  • 对于批量标记大量文档,有一些策略,这些策略并非互斥:

    • 对它们进行批处理。标签器不直接支持批处理,但作为一种技巧,您可以发送一堆文档,并在它们之间用一个字典中不存在的无意义的单词(如 "ZZYYXXAABBCC")连接起来。您需要跟踪这些字符偏移量,以便从结果中减去它们。

    • 为了进一步减少标记延迟,请考虑使用 EmbeddedSolrServer 嵌入 Solr。请参阅 EmbeddedSolrNoSerializeTest

    • 使用多个线程 - 也许与 Solr 可用的 CPU 内核数量一样多。