在solr / lucene中过滤存储在远程数据库中的字段的最佳方法?

时间:2011-04-13 14:50:55

标签: php mysql sql lucene solr

我有一个代表电影实体的大约10万个文档的索引。

用户可以将电影放在各种列表上(如收藏夹等)

这些列表存储在mysql数据库中,未在solr中编入索引。

我可以将用户ID存储在代表列表的多值字段中,但这非常糟糕,因为字段会非常非常长,索引也会出现问题。

所以目前我做以下(伪代码):

$favorites = SELECT document_id FROM favorites WHERE user_id = $user_id
$documents = 'http://solr.com:8393/select/?q=XYZ&fq=document_id:('.join(' OR ',$favorites);

这很有效,但过滤查询中的项目数量限制为1024(我试过)。也过滤查询加起来。所以,如果我有一个过滤查询,其中有500个值要过滤,我可以在另一个字段上有524过滤器的其他值。

现在没关系,因为我将每个列表的条目限制为1024,这是相当多的,但我认为这种方法非常笨拙并产生大量开销。

有没有更好的解决方案?就像编写直接连接数据库的solr模块一样?我想在php中做到这一点。

如果没有其他办法,我可以以某种方式提高1024限制吗?因为它现在工作得非常快!我认为使用好硬件不会有问题。

编辑:正如评论中所述,我在这里发布了我的原始架构和一个有效的示例查询。

<field name="film_id" type="int" indexed="true" stored="true" required="true"/> 
<field name="imdb_id" type="int" indexed="true" stored="true" /> 
<field name="parent_id" type="int" indexed="true" stored="true"/> 
<field name="malus" type="int" indexed="true" stored="true"/> 
<field name="type" type="int" indexed="true" stored="true"/> 
<field name="year" type="int" indexed="true" stored="true" termVectors="true"/> 
<field name="locale_title" type="string" indexed="false" stored="true"/> 
<field name="aka_title" type="filmtitle" indexed="true" stored="true" multiValued="true" omitNorms="true" termVectors="true" /> 
<field name="sort_title" type="string" indexed="true" stored="true"/> 
<field name="director" type="person" indexed="true" stored="true" multiValued="true" omitNorms="true"/> 
<field name="director_phonetic" type="person_phonetic" multiValued="true" omitNorms="true"/> 
<field name="actor" type="person" indexed="true" stored="true" multiValued="true" omitNorms="true"/> 
<field name="actor_phonetic" type="person_phonetic" multiValued="true" omitNorms="true"/> 
<field name="country" type="string" indexed="true" stored="true" multiValued="true"/> 
<field name="description" type="text" indexed="true" stored="true" /> 
<field name="genre" type="genre" indexed="true" stored="true" multiValued="true" termVectors="true"/> 
<field name="url" type="string" indexed="true" stored="true" multiValued="false"/> 
<field name="image_url" type="string" indexed="false" stored="true" multiValued="false"/>
<field name="rating" type="int" indexed="true" stored="true" required="false" default="50"/>
<field name="affiliate" type="string" indexed="true" stored="true" multiValued="true"/>
<field name="product_type" type="string" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="product_*" type="string" indexed="true" stored="true" multiValued="true"/>
<field name="blockbuster" type="boolean" indexed="true" stored="true" /> 
<copyField source="film_id" dest="id"/>
<field name="director_id" type="string" indexed="true" stored="true" multiValued="true" termVectors="true"/>
<field name="actor_id" type="string" indexed="true" stored="true" multiValued="true" termVectors="true"/>

theese是我对默认schema.xml的补充

可以查看示例搜索结果here

示例查询将是:

http://my-server.com:8983/solr/select/?
q=description:nazis
&fq=product_bluray:amazon
&fq=film_id:(1185616 1054606 88763 361748 78748)

此处用户将搜索以下电影:

  • 在亚马逊上作为蓝光
  • 在说明中使用“nazis”一词
  • 这是他最喜欢的名单

该列表包含带有ids 1185616 1054606 88763 361748 78748 的电影(文档),并存储在mysql数据库中。

ps:我不知道我是否很好地提出了这个问题,我希望它是可以理解的。如果没有,请随时编辑!

1 个答案:

答案 0 :(得分:3)

第一步是确保你真的想要使用Solr。看看你的模式,那里有很多很容易受到普通RDBMS和基本文本索引的影响。花半个小时看看postgresql,除非你已经确定一个普通的老式RDBMS带有一些额外的铃声,口哨声不会为你做。

Solr社区对此问题很感兴趣,但没有真正的解决方案。

显而易见的方法是,每当有人在多值字段中使用其用户名收藏时,重新索引“收藏”文档。当然,这是脑死亡,但这并不意味着它不会起作用,这取决于你的一个用户多么频繁地弄乱他/她的收藏列表。如果您的文档尺寸很小(我假设它们只有几K)并且您可以获得足够的硬件来将整个索引保留在内存中(可能因为您只有100K文档)这可能是考虑的方法。您可以通过构建一个可以实际适合可用内存的大小的索引来测试它并实现策略。看看它是否足够快。

如果人们不能一次性添加大量收藏,您也可以“批量”执行这些操作,如下所示:

  • 第1天:我在收藏夹中添加了10个项目。您将他们的ID粘贴在数据库中,并使用该ID列表来过滤我的查询。
  • Night 1:您更新了当天所有人都喜欢的所有文档,并将我的用户名添加到“favoritedBy”multiValued字段中。从数据库中删除我最喜欢的列表,因为它现在在Solr索引本身中表示。
  • 第2天:我在我的收藏夹中添加了三个项目。您对以下两者都进行了过滤:myusername和id :( newID1或newID2或newID3)。

如果人们每天添加合理数量的收藏并且您在晚上没有大量流量,这可能对您有用。