我使用 Zend Framework,因此使用Zend_Search_Lucene。这是分面搜索的纯 PHP 实现。您可以相对直接地定义自己的“文档”(作为数据的聚合)、权重轴和构建索引。根据我的经验,缺点是索引和查询比(例如)solr 慢得多。
更新 1
作为对评论的回应,这里有一个链接:我如何使用 Zend_Search_Lucene 进行空间搜索。那里的代码演示了一些事情:
- 第 54-62 行显示了如何将“文档”添加到索引中。在此示例中,文档只有两个字段(经度和纬度),但您明白了。只需将其放在一个循环中并将文档添加到您的索引中。在生产操作中,我会跟踪数据的变化,并在进入索引文档的任何数据发生变化时更新索引。最初的导入非常慢——根据经验,我发现算法至少是 O(n log n) 和一个相当大的 K,而 solr 更像是 O(log n)。
- 第 42-52 行显示了如何搜索索引。这个搜索比平时复杂一点,因为我必须以与索引中编码相同的方式对经度和纬度进行编码。文章解释了为什么必须这样做,但我只想说:如果你只有文本数据,索引搜索并不难。
- 第 40 行正在创建索引,前两个项目符号中提到的“添加”和“搜索”都需要该索引。请注意,将索引保持在快速介质(如 SD 存储)上会降低算法中的 K,但它仍然(根据经验,而不是分析)O(n log n)。
- 第 1-38 行是将经度和纬度标准化为 Zend_Search_Lucene 支持的格式所需的助手。同样,如果您只有文本数据,则不需要这种复杂性。
更新 2回应关于性能的评论。将索引放在快速介质(SD、带同步的 RAM 磁盘等)上会加快速度。使用未存储的字段也有一点帮助。这两者都减少了经验 O(n log n) 中的常数,但主要问题仍然是 n 乘数。Zend 似乎在做的是,在每次添加时,将大部分或所有先前添加到索引中的内容重新洗牌。据我所知,这是在索引构建期间发挥作用的算法,无法修改。
我绕过 n 乘数的方法是使用基于词干查询的Zend 页面缓存(因此,如果有人键入“blueberries”、“blueberry”、“blue berry”、“blu bary”等,它们都会被词干并固定为 soundex 语音“blue-bear-ee”)。常见查询几乎可以立即获得结果,并且由于特定域的读取量大且插入延迟,因此这是一个可以接受的解决方案。显然,一般情况下并非如此。
在其他情况下,有setResultSetLimit() 方法,当与评分一起使用时,将更快地返回结果。如果您不关心所有可能的结果,只关心前 N 个结果,那么这就是要走的路。
最后,所有这些经验都是关于 Zend 1.x 的。我不知道这是否已在 2.x 中解决。