如何在Solr上的multiValue字段中提升重复值

时间:2013-11-02 16:56:36

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

我的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

2 个答案:

答案 0 :(得分:4)

声明

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

  • 区域设置创建一个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集合1中提供)

第一个解决方案(订购):

某些function可以订购结果。所以我们可以按字段中的出现次数(termfreq函数)进行排序:

  • 如果使用copyField,则排序查询将为:termfreq(locales_text,'en_US') DESC

  • 如果区域设置属于text_general类型,则排序查询将为: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')查看匹配数量。

要记住一件事 - 它是 订单 功能,而不是增强功能。如果您希望根据多场比赛提高得分,您可能会对第二种解决方案更感兴趣。

我在结果中加入了分数来证明@arun正在谈论的内容。您可以看到分数不同(可能是长度)...对于多值字符串而言,相当意想不到(对我而言)它是相同的。

第二种解决方案(提升):

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

  • 如果locales属于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 - 它应该具有相同的结果。

答案 1 :(得分:0)

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&wt=xml&debugQuery=on(然后右键单击浏览器并查看页面源以查看正确缩进的分数计算)。我相信你会看到lengthNorm对doc1的得分较低。

要使该字段的长度不对分数产生影响,您需要将其禁用。为该字段设置omitNorms=true。 (参考:http://wiki.apache.org/solr/SchemaXml)然后看看分数是多少。