#php #javascript #ajax #mysqli
Здравствуйте!
Я собираюсь сделать на сайте живой поиск (как в Google). Нашел достаточно много материалов
на эту тему. Лишь из-за одного момента я не могу приступить. Мой уровень знаний достаточно
мал и я не могу понять как мне решить следующую проблему:
Вот с сайта, при помощи Ajax поступает запрос на .php скрипт, который должен взять
из базы инфу. Вопрос - как можно быстро подключиться к бд или вообще сделать это заранее?
Объяснений я не нашел. Я так понял, что больше всего времени тратиться именно на подключение
к бд. Подключаться к ней после ввода каждого символа не получится. Все будет виснуть.
Во всех примерах, которые я видел просто писалось $mysqli->query(...). Строк подключения
там не было, словно оно уже как таковое имеется.
Я попытался вникнуть в систему "постоянных подключений", но так и не разобрался,
что к чему. К тому же там ограничения на кол-во одновременных соединений есть.
Очень прошу помочь с этим вопросом. Из-за него буквально стоит весь проект.
Ответы
Ответ 1
О том, как реализовать автодополнение наиболее оптимально. Просто поиск в базе однозначно неэффективен: на один ввод пользователя может прийтись до десятка запросов, каждый из которых лезет в базу, в которой теоретически могут лежать хоть миллионы записей, а всякие wildcard поиски обожают страдать, за ними надо внимательно следить, чтобы они действительно использовали индексы; кроме того, упоротый фронтенд, используя плечо в виде количества приходящих на сайт, может легко все положить, отправляя по запросу на каждую букву и мультиплицируя входящий трафик в два-три-пять раз. В общем, путь рабочий, и, более того, при должном усердии, работающий быстро, но не моментально и требующий поддержки; кроме того, каждый инсерт-апдейт будет кромсать индекс и быстродействие. Как решить эту проблему? Во-первых, можно по старой привычке запихнуть все в оперативную память, во-вторых, можно использовать эффективные алгоритмы. Если в случае с базой и индексом скорость поиска будет составлять n или log n в лучшем случае (n - количество записей, по которым производится поиск), то префиксное дерево / префиксный бор и суффиксный автомат позволяют свести скорость поиска до максимальной длины строки - то есть, до константы. Про суффиксный автомат я не могу сказать, так как у меня все нет времени дочитать и собрать воедино прочитанное, а префиксный бор (далее - Trie), по факту, представляет собой почти что обычное дерево: Trie строится для некоторых последовательностей, по которым нужно выполнить поиск (в нашем случае это строки, или последовательности символов). Узел в Trie представляет собой структуру, в которой хранятся значения, о которых будет сказано чуть позже, и ссылки на дочерние узлы в виде map (ассоциативного массива) - каждый дочерний узел сохраняется с ключом типа сущности из последовательности (в нашем случае ключом будет символ). В виде значений хранятся либо непосредственно искомые значения, либо ссылки на них (например, айдишники, хотя если с ними придется еще раз лезть в базу, то этоабсолютно неэффективно). При заполнении Trie последовательности преобразуются в ветви, идущие из начального узла, и в узел, соответствующий последней сущности из последовательности записывается значение, соответствующее этой последовательности. Если я реализую поиск по продуктам, и мне попадется запись "молоко", то я сооружу из нее ветвь из шести узлов (если они еще не существуют в этот момент), и в последний узел запишу сам продукт. Если после этого мне попадется "молоковод", то я сооружу ветвь из девяти узлов (первые шесть из которых уже существуют), и в "д" я запишу непосредственно молоковода. Зачем это все нужно? В случае, если а) загрузить это все в оперативную память, б) держать это там между запросами, чтобы не выгружать каждый раз (здесь с PHP будут проблемы, да, но демонов никто не отменял) и в) выгрузить вообще всю информацию, которая должна выдаваться при поиске (а это редко больше чем две-три строки), то поиск первых N результатов по такому дереву будет выполняться за миллисекунду даже на хреновом железе. Для поиска достаточно просто разложить строку на последовательность символов, найти соответствующий узел, и наполнять корзину поиска из текущего, а потом и дочерних узлов до тех пор, пока дочерние узлы не кончатся или корзина не заполнится доверху. В среднем по больнице сложность поиска будет составлять где-нибудь шестнадцать символов, что до невероятности безумно прекрасно по сравнению с полным проходом всего массива. Единственная проблема Trie - это то, что по ней осуществляется префиксный поиск, и для поиска подстроки придется скармливать ей суффиксы один за одним (эффективный нечеткий поиск вообще сложно представить); также для эффективного поиска обычно рядом надо держать обычный мап вида, где и хранить сами данные, а в Trie лишь id искомых данных. По поводу расхода памяти - если представить, что на каждую структуру расходуется даже один килобайт памяти (что обычно оверкилл), то на каждую тысячу элементов будет расходоваться один мегабайт, что, в общем-то, копейки для современных машин. Ну и, конечно, нужно не забывать скидывать внутрь последовательности (строки) с предварительным преобразованием - Trie не найдет вам строку, если в ее начале оказался лишний пробел, а для регистронезависимого поика нужно скидывать все и искать в одном регистре. И, конечно, Trie надо регулярно обновлять по мере обновления сущностей в базе - лучше всего реализовать одновременно и функционал полной перезагрузки раз в N минут, и функционал обновления отдельной сущности при добавлении / удалении / апдейте. Ответ 2
Нашел ответ. На странице, на которой будет производиться живой поиск, необходимо создать постоянное соединение с помощью mysqli: /* Пермаментное подключение к БД */ $pMysqli = new mysqli('p:'.DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME); Для того, чтобы подключение было постоянным, необходимо добавить префикс "p:". Об этом я знал. После этого, в начале php скрипта, к которому обращается ajax, необходимо написать ту же строчку. Если соединение уже существует, то никакого подключения не состоится, зато у вас уже будет объект соединения. Пример: Страница, на которой есть форма живого поиска - somepage.php Обработчик Ajax запроса - handler.php query("SELECT Content FROM TestTable ORDER BY Content LIMIT 1"); /* Работа с полученными данными */ ?>
Комментариев нет:
Отправить комментарий