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

The*_*can 8 php mysql sql lucene solr

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

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

这些列表存储在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);
Run Code Online (Sandbox Code Playgroud)

这工作得非常快,但过滤查询中的项目数量限制为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"/>
Run Code Online (Sandbox Code Playgroud)

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

可在此处查看示例搜索结果.

示例查询将是:

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

在这里,用户将搜索以下电影:

  • 在亚马逊上作为蓝光提供
  • 在说明书中有"纳粹"一词
  • 这是他最喜欢的名单上的

该列表包括具有ID 1185616 1054606 88763 361748 78748的电影(文档)并存储在mysql数据库中.

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

Bil*_*ber 4

第一步是确保您确实想要使用 Solr。查看您的架构,其中有很多内容容易受到具有基本文本索引的普通 RDBMS 的影响。花半个小时看看 postgresql,除非您已经确定带有一些额外功能的常规老式 RDBMS 不适合您。

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

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

如果人们没有一次性添加大量的收藏夹,您也可以“批处理”这些操作,如下所示:

  • 第一天:我将十件商品添加到我的最爱中。您将他们的 ID 保存在数据库中,并使用该 ID 列表来过滤我的查询。
  • 第 1 晚:您更新白天被任何人收藏的所有文档,将我的用户名添加到“favoritedBy”多值字段中。从数据库中删除我最喜欢的列表,因为它现在在 Solr 索引本身中表示。
  • 第二天:我将另外三件商品添加到我的最爱中。您可以根据 favorited:myusername 和 id:(newID1 OR newID2 or newID3) 进行过滤。

如果人们每天添加一定数量的收藏夹并且您晚上的流量不是很多,那么这可能对您有用。