建议

Solr 建议组件(SuggestComponet)为用户在查询词条时提供自动的建议。在你自己的应用程序使用它来实现强大的自动建议特性。

虽然使用语法检查(Spell checking)功能提供自动建议是可行的,但是 Solr 专门设计了 SuggestComponet 来实现该功能。这个方法利用了 Lucene 的建议实现且支持 Lucene 提供的所有查找实现

建议的主要特性

  • 可插拔的查找实现
  • 可插拔的词典,带来选择词典实现的灵活性
  • 分布式支持

在 Solr 的 techproducts 示例里已在 solrconfig.xml 里配置了新的建议实现。了解更多的搜索组件,参考 RequestHandlers and SearchComponents in SolrConfig

在 solrconfig.xml 里配置建议

techproducts 示例的 solrconfig.xml 已配置了 suggest 搜索组件和一个 /suggest 请求处理器。以此为你的配置基础,或按下面描述的从头创建配置

添加建议搜索组件

首先是在 solrconfig.xml 里添加一个搜索组件,并让它使用建议组件,如下

<searchComponent name="suggest" class="solr.SuggestComponent">
  <lst name="suggester">
  <str name="name">mySuggester</str>
  <str name="lookupImpl">FuzzyLookupFactory</str>
  <str name="dictionaryImpl">DocumentDictionaryFactory</str>
  <str name="field">cat</str>
  <str name="weightField">price</str>
  <str name="suggestAnalyzerFieldType">string</str>
  <str name="buildOnStartup">false</str>
  </lst>
</searchComponent>

建议搜索组件参数

建议搜索组件有几个配置参数。查找实现(lookupImpl,如何在建议词典里找到词条)和词典实现(dictionaryImpl,如何在建议词典里保存词条)的选择基于几个必须的参数。不管是哪种查找或词典的实现,下面列出的是主要的参数

参数 说明
searchComponentName 搜索组件名称
name 建议的名称,可以在 URL 参数和 SearchHandler 配置里引用该名称。可以有多个建议(?)
lookupImpl 查找实现。有几个可用的实现,参考 Lookup Implementations。如果未设置,默认为 JaspellLookupFactory
dictionaryImpl 词典实现。有几个可用的实现,参考 Dictionary Implementations。如果未设置,默认的词典实现为 HighFrequencyDictionaryFactory,如果 sourceLocation 使用的话,则为 FileDictionaryFactory
field 索引里的一个字段,用来作为建议词条的基础,如果 sourceLocation 为空(意味着 FileDictionaryFactory 之外的词典实现)那么这个字段里索引的词条被使用。
要作为建议的基础,这个字段必须是存储的。你也许想要用 copyField 来创建一个包含文档里其他字段的建议字段。无论如何,你希望该字段的分析最小化,所以,一个额外的选项是在你的 schema 创建一个只使用基本的分词器或过滤器的字段,如下面的一个字段

<fieldType class="solr.TextField" name="textSuggest" positionIncrementGap="100">
<analyzer>
<tokenizer class="solr.StandardTokenizerFactory"/>
<filter class="solr.StandardFilterFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
</fieldType>

但是,如果你想要在词条上作更多的分析,如果使用 AnalyzingLookupFactory 作为查找实现,你就有了在索引和查询时分析的字段选项
sourceLocation 词典文件路径,用于 FileDictionaryFactory。如果该值为空,那么主索引将被用于词条和权重的来源
storeDir 保存词典文件的路径
buildOnCommit 或 buildOnOptimize 如果为 true,查找数据结构在软提交后会被重建。默认为 false,查找数据仅在 URL 参数 suggest.build=true 时重建。buildOnCommit 会在每次软提交时重建词典,buildOnOptimize 仅在索引优化时重建词典。某些查找实现创建(建议)非常耗时,尤其是对大索引,这种场景下,不推荐在有高频的软提交时使用 buildOnCommitbuildOnOptimize,替代的是,推荐低频的手工创建建议,使用 suggest.build=true 发送请求
buildOnStartup true 表示在 Solr 启动时或 core 重载时创建查找数据结构。如果该参数未指定,会检查查找数据结构是否存在于磁盘,如果不存在则创建。设为 true 会导致 core 在加载(或重载)时更耗时,因为需要创建建议数据结构,而这是个耗时的操作。通常把这个设置设为 false,并手工创建建议,使用 suggest.build=true 发送请求

查找实现

lookupImpl 参数定义了在建议索引里查找词条的算法。有几种实现可供选择,有些还需要额外的配置参数

AnalyzingLookupFactory

该实现首先分析输入文本,然后将分析过的结果添加到一个加权的 FST(?),在查找时同样这么做。

这个实现使用下面列出的额外的属性

  • suggestAnalyzerFieldType: 在构建和查询时分析建议所用的字段类型
  • exactMatchFirst: 默认=true,首先返回准确的建议,即便其前缀或其他字符串在 FST 里有更高的权重。(这个应该是表示优先返回完全匹配的建议)
  • preserveSep: 默认=true,保留词元之间的分隔符。这表示对分词敏感(例如,baseball 和 base ball 是不同的)
  • preservePositionIncrements: 如果为 true,建议会保留位置增量。这表示构建建议时保留位置间隔的分词过滤器更受尊重(?)。默认=false
FuzzyLookupFactory

AnalyzingSuggester 的扩展,但是模糊性。Levenshtein 算法用于衡量相似性。

该实现使用下面的额外属性

  • exactMatchFirst: 默认=true,首先返回准确的建议,即便其前缀或其他字符串在 FST 里有更高的权重。(这个应该是表示优先返回完全匹配的建议)
  • preserveSep: 默认=true,保留词元之间的分隔符。这表示对分词敏感(例如,baseball 和 base ball 是不同的)
  • maxSurfaceFormsPerAnalyzedForm: Maximum number of surface forms to keep for a single analyzed form. When there are too many surface forms we discard the lowest weighted ones.
  • maxGraphExpansions: When building the FST ("index-time"), we add each path through the tokenstream graph as an individual entry. This places an upper-bound on how many expansions will be added for a single suggestion. The default is -1 which means there is no limit.
  • preservePositionIncrements: 如果为 true,建议会保留位置增量。这表示构建建议时保留位置间隔的分词过滤器更受尊重(?)。默认=false
  • maxEdits: 可编辑的字符串最大数值。系统最大限制为 2,默认为 1
  • transpositions: If true, the default, transpositions should be treated as a primitive edit operation.
  • nonFuzzyPrefix: The length of the common non fuzzy prefix match which must match a suggestion. The default is 1.
  • minFuzzyLength: The minimum length of query before which any string edits will be allowed. The default is 3.
  • unicodeAware: 默认=false,如果为 true,则 maxEdits, minFuzzyLength, transpositions 和 nonFuzzyPrefix 参数以 unicode code 字符来计算而不是字节
AnalyzingInfixLookupFactory
BlendedInfixLookupFactory
FreeTextLookupFactory
FSTLookupFactory
TSTLookupFactory

简单紧凑的三叉树(Ternary Trie)的查找

WFSTLookupFactory
JaspellLookupFactory

来自 JsSpell 项目,基于三叉树但更加复杂的查找。如果想要更加复杂的匹配结果使用这个实现

词典实现

词典实现定义了词条如何存储。有多个选项,如果有必要的话,单个请求可以使用多个词典。

DocumentDictionaryFactory

词典包含:词条,权重和可选的来自索引的负荷(payload)

参数

  • weightField: 一个存储的字段,或DocValue 数值字段。该字段可选
  • payloadField: 一个存储的字段,可选的
  • contextField: 上下文过滤字段,注意只有某些查找实现支持过滤
DocumentExpressionDictionaryFactory

与 DocumentDictionaryFactory 一样,但是允许指定一个任意的表达式。

参数

  • weightExpression: 用于对建议评分的任意表达式,必须使用数值字段。该字段是必须滴
  • payloadField: 一个存储的字段,可选的
  • contextField: 上下文过滤字段,注意只有某些查找实现支持过滤
HighFrequencyDictionaryFactory
FileDictionaryFactory

多重词典

单个建议组件里可以包含多个词典实现。只需简单的分别定义建议,示例如下

<searchComponent name="suggest" class="solr.SuggestComponent">
  <lst name="suggester">
    <str name="name">mySuggester</str>
    <str name="lookupImpl">FuzzyLookupFactory</str>
    <str name="dictionaryImpl">DocumentDictionaryFactory</str>
    <str name="field">cat</str>
    <str name="weightField">price</str>
    <str name="suggestAnalyzerFieldType">string</str>
  </lst>
  <lst name="suggester">
    <str name="name">altSuggester</str>
    <str name="dictionaryImpl">DocumentExpressionDictionaryFactory</str>
    <str name="lookupImpl">FuzzyLookupFactory</str>
    <str name="field">product_name</str>
    <str name="weightExpression">((price * 2) + ln(popularity))</str>
    <str name="sortField">weight</str>
    <str name="sortField">price</str>
    <str name="storeDir">suggest_fuzzy_doc_expr_dict</str>
    <str name="suggestAnalyzerFieldType">text_en</str>
  </lst>
</searchComponent>

在查询里使用建议时,可以在请求里定义多个 'suggest.dictionary' 参数,引用搜索组件里定义的每个建议的名称即可。响应里会包含每个建议的小节。

添加建议请求处理器(Suggest Request Handler)

添加搜索组件以后,必须在 solrconfig.xml 里添加请求处理器(request handler)。这个请求处理器和其他的请求处理器一样,允许你配置默认参数来为建议请求服务。这个请求处理器的定义里必须包含之前定义的建议搜索组件。

<requestHandler name="/suggest" class="solr.SearchHandler" startup="lazy">
  <lst name="defaults">
    <str name="suggest">true</str>
    <str name="suggest.count">10</str>
  </lst>
  <arr name="components">
    <str>suggest</str>
  </arr>
</requestHandler>

建议请求处理器参数

参数 说明
suggest=true 该参数必须为 true
suggest.dictionary 在搜索组件里配置的词典组件的名称。该参数是必须滴,可以在请求处理器里设置,也可以在查询时通过参数传递
suggest.q 查找建议时用的查询
suggest.count 指定 Solr 返回的建议数量
suggest.cfq cfq = Context Filter Query,如果支持的话,用于过滤建议的上下文字段
suggest.build true 表示构建建议索引。仅在初次请求时有用;你应该不会想在每次请求时构建词典,尤其是在生产环境。如果想要保持词典最新,应该在搜索组件上使用 buildOnCommitbuildOnOptimize 参数
suggest.reload true 表示重载建议索引
suggest.buildAll true 表示构建所有的建议索引
suggest.reloadAll true 表示重载所有的建议索引

上下文过滤

上下文过滤(suggest.cfg)当前仅 AnalyzingInfixLookupFactory 和 BlendedInfixLookupFactory 支持,且仅当词典实现为 Document*Dictionary。其他实现将忽视过滤请求,返回未过滤的匹配。

用法示例

根据权重获取建议

这是最基本的建议,使用单个词典和单个 Slor core,示例

http://localhost:8983/solr/techproducts/suggest?suggest=true&suggest.build=true&suggest.dictionary=mySuggester&wt=json&suggest.q=elec

在这个例子里,有一个简单的请求:,suggest.q 参数指定字符串 'elec',suggest.build 参数指定构建建议词典(注意,你不会想要每次请求都构建建议词典,取而代之的是使用 buildOnCommit 或 buildOnOptimize,如果你定期改变文档)

示例的响应

{
  "responseHeader": {
    "status": 0,
    "QTime": 35
  },
  "command": "build",
  "suggest": {
    "mySuggester": {
      "elec": {
        "numFound": 3,
        "suggestions": [
          {
            "term": "electronics and computer1",
            "weight": 2199,
            "payload": ""
          },
          {
            "term": "electronics",
            "weight": 649,
            "payload": ""
          },
          {
            "term": "electronics and stuff2",
            "weight": 279,
            "payload": ""
          }
        ]
      }
    }
  }
}

多重词典

如果定义了多个词典,可以在查询里使用它们。示例查询

http://localhost:8983/solr/techproducts/suggest?suggest=true&suggest.dictionary=mySuggester&suggest.dictionary=altSuggester&wt=json&suggest.q=elec

在这个例子里,发送了 suggest.q 参数为字符串 'elec' 和 2 个 suggest.dictionary

示例的响应

{
  "responseHeader": {
    "status": 0,
    "QTime": 3
  },
  "suggest": {
    "mySuggester": {
      "elec": {
        "numFound": 1,
        "suggestions": [
          {
            "term": "electronics and computer1",
            "weight": 100,
            "payload": ""
          }
        ]
      }
    },
    "altSuggester": {
      "elec": {
        "numFound": 1,
        "suggestions": [
          {
            "term": "electronics and computer1",
            "weight": 10,
            "payload": ""
          }
        ]
      }
    }
  }
}

内容过滤

上下文过滤让你使用分离的上下文字段来过滤建议,例如分类,部门或其他。AnalyzingInfixLookupFactory 和 BlendedInfixLookupFactory 当前支持这个特性,当后台是用的 DocumentDictionaryFactory。

在你的建议配置里添加 contextField。这个示例将建议名称且按分类过滤

<!--solrconfig.xml-->

<searchComponent name="suggest" class="solr.SuggestComponent">
  <lst name="suggester">
    <str name="name">mySuggester</str>
    <str name="lookupImpl">AnalyzingInfixLookupFactory</str>
    <str name="dictionaryImpl">DocumentDictionaryFactory</str>
    <str name="field">name</str>
    <str name="weightField">price</str>
    <str name="contextField">cat</str>
    <str name="suggestAnalyzerFieldType">string</str>
    <str name="buildOnStartup">false</str>
  </lst>
</searchComponent>

示例的内容过滤建议查询

http://localhost:8983/solr/techproducts/suggest?suggest=true&suggest.build=true& \ 
suggest.dictionary=mySuggester&wt=json&suggest.q=c&suggest.cfq=memory

该建议将只返回产品标记为 cat=memory 的建议

results matching ""

    No results matching ""