1

首先是实际状态:有一个带有表格的 ZF2 应用程序。该表单包含一些自动完成字段(在前端使用jQuery Autocomplete实现)。

其背后的 SQL 语句如下所示:

SELECT name FROM countries WHERE countries.name LIKE %en%
-> should find "Arg[en]tina", "Arm[en]ia", "B[en]in", "Turkm[en]istan" etc.
or
SELECT name FROM countries WHERE countries.continent_id = 2
-> should find "Afghanistan", "Armenia", "Azerbaijan" etc. (2 = Asia)
or
SELECT name FROM countries WHERE countries.continent_id = 2 AND countries.name LIKE %en%
-> should find "Arm[en]ia", "Turkm[en]istan" etc. (2 = Asia)

当然,它会导致问题,即数据库被许多小的自动完成请求吓坏了。缓存应该会有所帮助——而且我已经开始实现Zend\Cache\Storage\Adapter\Apcu基于 - 的缓存机制。但后来我看到了下一个麻烦:使用像APCu这样的通用缓存我无法动态过滤结果。所以这样的缓存似乎不适用于自动完成的情况。

我很确定,这是一个常见问题,并且已经有解决方案。

如何在 ZF2 应用程序中实现自动完成功能的缓存机制?

4

1 回答 1

0

这里与 ZF2 无关。这完全是关于自定义搜索服务设计和挑战。

如果没有适当的缓存层和/或全文搜索引擎,构建这样的自动完成实现对于应用程序来说将是自杀。您可以在很短的时间内轻松实现数万次不必要的重复查询。

在“理想”的世界中,一个好的自动完成实现在底层使用全文搜索引擎,例如ElasticsearchApache Solr。并分别使用它们的Completion SuggesterSuggester组件。

无论如何,仅使用对象缓存和数据库仍然可以实现简单的自动完成功能。只有您需要一个帮助方法来为每个字母组合创建适当的“缓存键”。例如:

   function createKeyByQuery($str)
   {
      return 'autocomplete-prefix-'.(string) $str;
   }

并在您的suggest()方法中:

   public function suggest($keyword)
   {
       $key = $this->createKeyByQuery($keyword);
       if($this->cache->hasItem($key)) {
           return $this->cache->getItem($key);
       }

       // fetch form the database here
       $data = $this->db->query();
       $this->cache->setItem($key, $data);

       return $data;
   }

如果您的过滤器数量不多,也只需将它们作为键的一部分。在这种情况下,建议方法的签名将是:

  public function suggest($keyword, array $filters = []);

密钥生成器需要更新:

   function createKeyByQuery($str, array $filters = [])
   {
      return 'autocomplete-prefix-' . (string) $str . md5(serialize($filters));
   }

此解决方案可能不适合复杂/域相关数据,因为它具有相当大的失效挑战。例如。您将如何找到在有效负载中保存“阿根廷”的缓存键?

由于您只处理国家和大洲列表作为过滤器,它应该可以解决问题。

对于england关键字和两个不同的过滤器,总共有 10 个过滤器选项,将有 10x2x7 = 140 个不同的缓存键。对于具有 5 个选项的单个过滤器,5x1x7 = 37 个不同的键。

APCu 是此实现的不错选择。

希望能帮助到你。

于 2016-10-30T23:54:06.660 回答