【问题标题】:How to boost repeated values in a multiValue field on Solr如何在 Solr 上的多值字段中提升重复值
【发布时间】:2013-11-02 16:56:35
【问题描述】:

我的 solr 索引的 multiValue 字段中有一些重复(相同的字符串)数据,我想通过该字段中的匹配计数来提升文档。例如:

doc1 : { locales : ['en_US', 'de_DE', 'fr_FR', 'en_US'] }
doc2 : { locales : ['en_US'] }

当我运行查询q=locales:en_US 时,我希望看到顶部的 doc1,因为它有两个“en_US”值。提升此类数据的正确方法是什么?

我应该使用特殊的标记器吗?

Solr 版本为:4.5

【问题讨论】:

  • 你的字段类型是字符串吗?您是否先运行查询并获取 doc2?
  • yes 类型是字符串并首先获取 doc2,但字段中值的顺序会因文档而异。在 doc1 上有问题 en_US 第一和 de_DE 第二。我正在尝试通过值的计数而不是字段内的顺序来获取匹配的文档。

标签: solr full-text-search solr-boost


【解决方案1】:

免责声明

为了使用以下任一解决方案,您需要进行以下任一更改:

  • locales创建一个copyField:
<field name="locales" type="string" indexed="true" stored="true" multiValued="true"/>
<!-- No need to store(stored="false") locales_text as it will only be used for searching/sorting/boosting -->
<field name="locales_text" type="text_general" indexed="true" stored="false" multiValued="true"/>
<copyField source="locales" dest="locales_text"/>
  • 将语言环境的类型更改为“text_general”(该类型在标准 solr 集合中提供)

第一个解决方案(排序):

结果可以通过一些function 排序。所以我们可以按字段中出现的次数(termfreq 函数)排序:

  • 如果使用了 copyField,则 sort 查询将是:termfreq(locales_text,'en_US') DESC

  • 如果 locales 是 text_general 类型,则 sort 查询将是:termfreq(locales,'en_US') DESC

copyField 选项的响应示例(text_general 类型的结果相同):

<?xml version="1.0" encoding="UTF-8"?>
<response>

<lst name="responseHeader">
  <int name="status">0</int>
  <int name="QTime">1</int>
  <lst name="params">
    <str name="fl">*,score</str>
    <str name="sort">termfreq(locales_text,'en_US') DESC</str>
    <str name="indent">true</str>
    <str name="q">locales:en_US</str>
    <str name="_">1383598933337</str>
    <str name="wt">xml</str>
  </lst>
</lst>
<result name="response" numFound="2" start="0" maxScore="0.5945348">
  <doc>
    <arr name="locales">
      <str>en_US</str>
      <str>de_DE</str>
      <str>fr_FR</str>
      <str>en_US</str>
    </arr>
    <str name="id">4f9f71f6-7811-4c22-b5d6-c62887983d08</str>
    <long name="_version_">1450808563062538240</long>
    <float name="score">0.4203996</float></doc>
  <doc>
    <arr name="locales">
      <str>en_US</str>
    </arr>
    <str name="id">7f93e620-cf7b-4b90-b741-f6edc9db77c9</str>
    <long name="_version_">1450808391856291840</long>
    <float name="score">0.5945348</float></doc>
</result>
</response>

您也可以使用fl=*,termfreq(locales_text,'en_US')查看匹配的数量。

要记住一件事 - 它是 order 函数,而不是 boost 函数。如果您更愿意根据多个匹配来提高分数,那么您可能会对第二种解决方案更感兴趣。

我将分数包含在结果中以证明 @arun 所说的内容。你可以看到分数是不同的(可能是长度)......非常意外(对我来说)对于多值 string 它是相同的。

第二种解决方案(Boosting):

  • 如果使用了 copyField,则 查询 将是:{!boost b=termfreq(locales_text,'en_US')}locales:en_US

  • 如果语言环境是 text_general 类型,则 查询 将是:{!boost b=termfreq(locales,'en_US')}locales:en_US

copyField 选项的响应示例(text_general 类型的结果相同):

<?xml version="1.0" encoding="UTF-8"?>
<response>

<lst name="responseHeader">
  <int name="status">0</int>
  <int name="QTime">0</int>
  <lst name="params">
    <str name="lowercaseOperators">true</str>
    <str name="fl">*,score</str>
    <str name="indent">true</str>
    <str name="q">{!boost b=termfreq(locales_text,'en_US')}locales:en_US</str>
    <str name="_">1383599910386</str>
    <str name="stopwords">true</str>
    <str name="wt">xml</str>
    <str name="defType">edismax</str>
  </lst>
</lst>
<result name="response" numFound="2" start="0" maxScore="1.1890696">
  <doc>
    <arr name="locales">
      <str>en_US</str>
      <str>de_DE</str>
      <str>fr_FR</str>
      <str>en_US</str>
    </arr>
    <str name="id">4f9f71f6-7811-4c22-b5d6-c62887983d08</str>
    <long name="_version_">1450808563062538240</long>
    <float name="score">1.1890696</float></doc>
  <doc>
    <arr name="locales">
      <str>en_US</str>
    </arr>
    <str name="id">7f93e620-cf7b-4b90-b741-f6edc9db77c9</str>
    <long name="_version_">1450808391856291840</long>
    <float name="score">0.5945348</float></doc>
</result>
</response>

您可以看到分数发生了显着变化。第一个文档的得分是第二个的两倍(因为有两个匹配,每个得分为 0.5945348)。

第三种解决方案(omitNorms=false)

根据@arun 的回答,我认为还有第三种选择。

如果您将字段转换为(例如)text_general 并为该字段设置 omitNorms=true - 它应该具有相同的结果。

【讨论】:

    【解决方案2】:

    Solr 中的默认标准请求处理程序不仅仅使用术语频率来计算分数。除了词频,它还使用字段的长度。请参阅lucene scoring algorithm,上面写着:

    lengthNorm - computed when the document is added to the index in accordance with the number of tokens of this field in the document, so that shorter fields contribute more to the score.

    由于 doc2 的字段较短,因此它的得分可能更高。在查询中使用fl=*,score 检查结果的分数。要了解 Solr 是如何得出分数的,请使用fl=*,score&amp;wt=xml&amp;debugQuery=on(然后右键单击浏览器并查看页面源代码以查看正确缩进的分数计算)。我相信您会看到 lengthNorm 导致 doc1 得分较低。

    要使字段长度不计入分数,您需要禁用它。为该字段设置omitNorms=true。 (参考:http://wiki.apache.org/solr/SchemaXml)然后看看分数是多少。

    【讨论】:

    • 如 solr schema cmets 中所述 - 1.5: omitNorms defaults to true for primitive field types (int, float, boolean, string...) 对于此类字段,应显式打开 on(是否应显式关闭所有其他字段 off)。
    猜你喜欢
    • 1970-01-01
    • 2012-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-29
    • 1970-01-01
    相关资源
    最近更新 更多