Сначала фактическое состояние: Есть приложение ZF2 с формой. Форма содержит несколько полей автозаполнения (реализовано на стороне интерфейса JQuery Автозаполнение).
Операторы 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 для функции автозаполнения?
Здесь нет ничего общего с ZF2. Все дело в индивидуальном дизайне службы поиска и его проблемах.
Без надлежащего уровня кэширования и / или механизма полнотекстового поиска, создание реализации автозаполнения, такой, что было бы самоубийством для приложения. Вы можете легко выполнить десятки тысяч ненужных повторных запросов за очень короткое время.
В «идеальном» мире хорошая реализация автозаполнения использует механизм полнотекстового поиска, такой как Elasticsearch или же Apache Solr. И использует их Завершение предложения а также 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 — хороший выбор для этой реализации.
Надеюсь, поможет.
Других решений пока нет …