我有一个包含大约 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"/>
这些是我对默认 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)
用户会在这里搜索以下电影:
- 在亚马逊上以蓝光格式提供
- 在描述中有“纳粹”一词
- 并且在他最喜欢的 list 上
该列表包括 ID 为 1185616 1054606 88763 361748 78748 的电影(文档),并存储在 mysql 数据库中。
ps:不知道我提的问题好不好,希望大家看得懂。如果没有,请随时编辑!
最佳答案
第一步是确保您确实想要使用 Solr。查看您的架构,其中有很多内容容易受到具有基本文本索引的普通 RDBMS 的影响。花半小时看看 postgresql,除非您已经确定带有一些额外功能的常规好老式 RDBMS 不适合您。
Solr 社区对此问题很感兴趣,但没有真正的解决方案。
最明显的方法是,每当有人在多值字段中用他们的用户名收藏一个“收藏的”文档时,就重新索引该文档。当然,这是脑死亡,但这并不意味着它不会起作用,这取决于您的某个用户多久弄乱他/她的收藏夹列表。如果您的文档很小(我假设它们只有几 K)并且您可以获得足够的硬件来将整个索引保存在内存中(可能因为您只有 100K 文档)这可能是要考虑的方法.您可以通过构建一个实际适合可用内存大小的索引来测试它并实现该策略。看看它是否足够快。
如果人们不一次添加大量收藏夹,您也可以“批处理”这些操作,如下所示:
- 第 1 天:我将 10 件商品添加到我的收藏夹中。您将他们的 ID 保存在数据库中,并使用该 ID 列表来过滤我的查询。
- 第 1 晚:您更新白天任何人收藏的所有文档,将我的用户名添加到“favoritedBy”多值字段。从数据库中删除我最喜欢的列表,因为它现在在 Solr 索引本身中表示。
- 第 2 天:我又添加了三个项目到我的收藏夹中。您过滤 favored:myusername 和 id:(newID1 OR newID2 or newID3)。
如果人们每天添加合理数量的收藏夹并且您晚上的流量不多,这可能对您有用。
关于php - 在 solr/lucene 中过滤存储在远程数据库中的字段的最佳方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5651192/