Как реализовать кэширование на стороне сервера для автозаполнения в приложении ZF2?

Сначала актуальное состояние: есть приложение ZF2 с формой. Форма содержит несколько полей автозаполнения (реализовано на стороне внешнего интерфейса с помощью http://jqueryui.com/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 для функции автозаполнения?

1 ответ

Здесь нет ничего общего с ZF2. Все дело в индивидуальном дизайне службы поиска и его проблемах.

Без надлежащего уровня кэширования и / или механизма полнотекстового поиска создание реализации автозаполнения, такой, что было бы самоубийством для приложения. Вы можете легко выполнить десятки тысяч ненужных повторных запросов за очень короткое время.

В "идеальном" мире хорошая реализация автозаполнения использует механизм полнотекстового поиска, такой как Elasticsearch или Apache Solr. И использует их компоненты Completion Suggester и Suggester соответственно.

В любом случае, простая функция автозаполнения все еще достижима, используя только кэш объектов и базу данных. Только вам нужен вспомогательный метод для создания правильного "ключа кеша" для каждой комбинации букв. Например:

   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 - хороший выбор для этой реализации.

Надеюсь, поможет.

Другие вопросы по тегам