Поиск по сайту с reindexer

Реализация метода поиска

Хендлер

На уровне REST API обработчик — это обычный хэндлер fasthttp. Его основная задача — получить параметры запроса, вызвать метод поиска в репозитории и отдать ответ клиенту.


Основную задачу обращения к поиску выполняет метод репозитория — он формирует запрос (Query) в Reindexer, получает ответ и преобразует ответ из в массив указателей на модели .

Формирование DSL и правил поиска

Обычно, поисковая строка сайта предполагает ввод запроса обычным человеческим языком, например, «Большие данные в науке» или «Rust vs C++», однако, поисковые движки требуют передачи запроса в формате специального DSL, в котором указывается дополнительные параметры поиска.

В DSL указывается по каким полям будет происходить поиск, подстраиваются релевантности — например, в DSL можно задать, что результаты, найденные по полю «заголовок»- более релевантные, чем результаты в поле «текст поста». Так же, в DSL настраиваются опции поиска, например, искать ли только точные вхождения слова или заодно, искать слово с опечатками.

Reindexer — не исключение, он так же предоставляет для Application DSL интерфейс. Документация по DSL

За преобразование текста в DSL отвечает функция . Функция преобразовывает текст так:

Введеный текст DSL Комментарии
Большие данные Релевантность нахождения в поле — 1.6, в поле — 1.0
в остальных — 0.4. Искать слово во всех словоформах
как префикс или суффикс, а так же искать с опечатками и искать
все словоформы, , как суффикс или префикс

Examples

Creating an index

In order to be able to make full text search queries, you have to create an index.

Usage:

use TeamTNT\TNTSearch\TNTSearch;

$tnt = new TNTSearch;

$tnt->loadConfig([
    'driver'    => 'mysql',
    'host'      => 'localhost',
    'database'  => 'dbname',
    'username'  => 'user',
    'password'  => 'pass',
    'storage'   => '/var/www/tntsearch/examples/',
    'stemmer'   => \TeamTNT\TNTSearch\Stemmer\PorterStemmer::class//optional
]);

$indexer = $tnt->createIndex('name.index');
$indexer->query('SELECT id, article FROM articles;');
//$indexer->setLanguage('german');
$indexer->run();

Important: «storage» settings marks the folder where all of your indexes will be saved so make sure to have permission to write to this folder otherwise you might expect the following exception thrown:

SQLSTATE unable to open database file *

Note: If your primary key is different than set it like:

$indexer->setPrimaryKey('article_id');

Making the primary key searchable

By default the primary key is not searchable. If you wanna make it searchable, simply run:

$indexer->includePrimaryKey();

Searching

Searching for a phrase or keyword is trivial

use TeamTNT\TNTSearch\TNTSearch;

$tnt = new TNTSearch;

$tnt->loadConfig($config);
$tnt->selectIndex("name.index");

$res = $tnt->search("This is a test search", 12);

print_r($res); //returns an array of 12 document ids that best match your query

// to display the results you need an additional query against your application database
// SELECT * FROM articles WHERE id IN $res ORDER BY FIELD(id, $res);

The ORDER BY FIELD clause is important, otherwise the database engine will not return the results in the required order.

Boolean Search

use TeamTNT\TNTSearch\TNTSearch;

$tnt = new TNTSearch;

$tnt->loadConfig($config);
$tnt->selectIndex("name.index");

//this will return all documents that have romeo in it but not juliet
$res = $tnt->searchBoolean("romeo -juliet");

//returns all documents that have romeo or hamlet in it
$res = $tnt->searchBoolean("romeo or hamlet");

//returns all documents that have either romeo AND juliet or prince AND hamlet
$res = $tnt->searchBoolean("(romeo juliet) or (prince hamlet)");

Fuzzy Search

The fuzziness can be tweaked by setting the following member variables:

public $fuzzy_prefix_length  = 2;
public $fuzzy_max_expansions = 50;
public $fuzzy_distance       = 2; //represents the Levenshtein distance;
use TeamTNT\TNTSearch\TNTSearch;

$tnt = new TNTSearch;

$tnt->loadConfig($config);
$tnt->selectIndex("name.index");
$tnt->fuzziness = true;

//when the fuzziness flag is set to true, the keyword juleit will return
//documents that match the word juliet, the default Levenshtein distance is 2
$res = $tnt->search("juleit");

PHP файл

Страница на сервере, вызываемая JavaScript выше, является PHP файлом с именем «livesearch.php».

Исходный код в «livesearch.php» ищет в XML файле заголовки, соответствующие строке поиска, и возвращает результат:

<?php $xmlDoc=new DOMDocument(); $xmlDoc->load(«links.xml»); $x=$xmlDoc->getElementsByTagName(‘link’); //получить параметр q из URL $q=$_GET; //поиск всех ссылок из XML файла, если длина q>0 if (strlen($q)>0) {   $hint=»»;   for($i=0; $i<($x->length); $i++) {     $y=$x->item($i)->getElementsByTagName(‘title’);     $z=$x->item($i)->getElementsByTagName(‘url’);     if ($y->item(0)->nodeType==1) {       //найти ссылку, соответствующую тексту поиска       if (stristr($y->item(0)->childNodes->item(0)->nodeValue,$q)) {         if ($hint==»») {           $hint=»<a href='» .           $z->item(0)->childNodes->item(0)->nodeValue .           «‘ target=’_blank’>» .           $y->item(0)->childNodes->item(0)->nodeValue . «</a>»;         } else {           $hint=$hint . «<br /><a href='» .           $z->item(0)->childNodes->item(0)->nodeValue .           «‘ target=’_blank’>» .           $y->item(0)->childNodes->item(0)->nodeValue . «</a>»;         }       }     }   } } // Установить результат в «Нет вариантов» если подсказка не найдена // или к найденным значениям if ($hint==»») {   $response=»Нет вариантов»; } else {   $response=$hint; } //вывод ответа echo $response; ?>

Если какой-либо текст, отправленный из JavaScript , происходит следующее:

  • Загрузка XML файла в новый объект XML DOM
  • Циклически просматривайте все элементы , чтобы найти совпадения из текста, отправленного из JavaScript
  • Задает правильный url и заголовок в переменной . Если найдено более одного совпадения, все совпадения добавляются в переменную
  • Если совпадений не найдено, переменной присваивается значение

Объяснение примера — HTML страницы

Когда пользователь вводит символ в поле ввода выше, выполняется функция . Функция запускается с помощью событие :

<html> <head> <script> function showResult(str) {  if (str.length==0) {    document.getElementById(«livesearch»).innerHTML=»»;     document.getElementById(«livesearch»).style.border=»0px»;    return;  }  if (window.XMLHttpRequest) {    // код для IE7+, Firefox, Chrome, Opera, Safari    xmlhttp=new XMLHttpRequest();   }else {  // код для IE6, IE5    xmlhttp=new ActiveXObject(«Microsoft.XMLHTTP»);  }  xmlhttp.onreadystatechange=function() {    if (this.readyState==4 && this.status==200) {     document.getElementById(«livesearch»).innerHTML=this.responseText;       document.getElementById(«livesearch»).style.border=»1px solid #A5ACB2″;     }  }  xmlhttp.open(«GET»,»livesearch.php?q=»+str,true);  xmlhttp.send();} </script> </head> <body> <form> <input type=»text» size=»30″ onkeyup=»showResult(this.value)»> <div id=»livesearch»></div> </form> </body> </html>

Объяснение исходного кода:

Если поле ввода пустое , функция очищает содержимое заполнителя livesearch и выводит из функции.

Если поле ввода не пустое, функция выполняет следующее:

Создание объекта

Создайте функцию, которая будет выполняться, когда ответ сервера будет готов Отправить запрос в файл сервера Обратите внимание, что в URL адрес добавляется параметр (с содержимым поля ввода)

Поиск по сайту php

  1. -> база данных
  2. -> файлы
    1. DW — search 1.2
    2. Скачать на странице
  1. Алгоритм поиска по сайту — нужно взять контент страницы,(либо ту строку базы данных, которая отвечает за контент) и проверить на совпадение с искомым словом, для этого будем использовать функцию и выдать на какой странице данное совпадение находится.

    И далее в цикле проверить все файлы или строки в базе на совпадение!

    Все просто!

  2. Для данного примера есть архив

    04.05.2020Друзья!

    Я уже давно не занимался базами данных, поэтому, никак проверить не смогу работоспособность данного скрипта!

    НО! Схематично могу набросать, как бы я делал поиск по базе данных сайта.

    Нам понадобится:

    Берем скрипт вывода из базы данных

    Все что внутри цикла while удаляем и туда вставляем:

    if(@substr_count($row, $poisk) and $poisk) { $line_count ++; $rezult .= ‘<a href =»‘.$row.'» target=»_blank»>’.$row.'</a>’ ; }

    Где :

    1). $row — столбец, отвечающий за контент 2). $row — столбец, отвечающий за ссылку 3). $row — столбец, отвечающий за заголовок

    Ниже скрипта располагаем форму для отправки запроса на поиск оп базе данных:

    <form method=»POST» action=»»> <input type=»text» name=»poisk»> <input type=»submit» name=»button» value=»ОТПРАВИТЬ»> </form>

    В самом верху страницы располагаем функцию собственную функцию strtolower

    function my_strtolower($str) { $ru_array = array(‘А’ => ‘а’,’Б’ => ‘б’,’В’ => ‘в’,’Г’ => ‘г’,’Д’ => ‘д’, ‘Е’ => ‘е’,’Ё’ => ‘ё’,’Й’ => ‘й’,’Ж’ => ‘ж’,’З’ => ‘з’,’И’ => ‘и’,’К’ => ‘к’,’Л’ => ‘л’,’М’ => ‘м’,’Н’ => ‘н’,’О’ => ‘о’,’П’ => ‘п’,’Р’ => ‘р’,’С’ => ‘с’,’Т’ => ‘т’,’У’ => ‘у’,’Ф’ => ‘ф’,’Х’ => ‘х’,’Ц’ => ‘ц’,’Ч’ => ‘ч’,’Ш’ => ‘ш’,’Щ’ => ‘щ’,’Ъ’ => ‘ъ’,’Ы’ => ‘ы’,’Ь’ => ‘ь’,’Э’ => ‘э’,’Ю’ => ‘ю’,’Я’ => ‘я’); return strtr($str,$ru_array ); }

    Следующей строкой получаем данные из формы :

    if($_POST){ $poisk = strip_tags ( $_POST );}

    Пропускам данные через my_strtolower:

    $poisk = my_strtolower( $poisk );

  3. 04.05.2020Для данного параграфа у нас есть :

    Пример на отдельной странице.

    Скачать со страницы

    Описание обновлено!

    Если мы говорим о поиске по контенту на сайте, который сделан на файлах, то первое с чем мы сталкиваемся, против базы данных, как получить все ссылки на все файлы!?

    Другими словами, где у вас есть все ссылки вашего сайта!? Предположим, что все ваши ссылки есть в карте sitemap.XML — нам нужно извлечь все ссылки из данного файла, а потом в цикле проверить наличие искомого слова…

    Да! И функцию можете заменить на обычную strtolower(если она у вас работает) Теперь не нужно вставлять домен, он будет автоматически передаваться в переменную! $domen = $_SERVER.’://’.$_SERVER ; 1). Получаем из карты все содержимое в строку с помощью file_get_contents $ALL_pages = file_get_contents(‘https://dwweb.ru/sitemap.xml’); 2). Получаем в массив все ссылки из тегов loc с помощью preg_match_all: preg_match_all(«#<loc>(.+?)</loc>#i», $ALL_pages, $url); 3). Поскольку первой ячейкой у нас автоматически всегда будет домен, т.е. главная — нам эту ячейку надо удалить! $fruit = array_shift($url); 4). Получим путь до корневой переменная $home(она нам потом понадобится.)

    + Получим в переменную $poisk от правленный поисковый запрос.

    + все буквы приведем к нижнему регистру my_strtolower

    $home = $_SERVER;

    if($_POST){ $poisk = strip_tags ( $_POST );}

    $poisk = my_strtolower( $poisk );

    5). Создадим условие — будем проверять существование файла + путь заменим ранее полученный домен, на путь на сервере

    if($_POST)

    {

    if( $poisk )

    {

    for ($i = 0; $i < count($ALL_PAGES); $i++)

    {

    if( file_exists( str_replace( $domen , $home , $ALL_PAGES) ) )

    {

    6).

    Теперь весь контент страницы полученный в цикле через file_get_contents переведем в нижний регистр — my_strtolower и внутри получим путь на сревре заменив домен на $home

    Далее собственно поиск искомого слова в контенте substr_count

    + если что-то найдено, то создаем счетчик +1($line_count)

    + заносим в переменную $rezult адрес страницы, где это было найдено.

    $new = my_strtolower( file_get_contents( str_replace( $domen , $home , $ALL_PAGES) ) );

    if (substr_count($new, $poisk))

    {

    $line_count += 1;

    $rezult .= ‘<a href =»‘.$ALL_PAGES.'» target=»_blank»>’.$ALL_PAGES.'</a><br>’ ;

    7). Проверяем если счетчик существует, то выводим на экран переменную $vivod_info if($line_count)($vivod_info) 8). и далее если отправлен $rezult = ‘Отправлен пустой запрос’;

    Далее особо ничего интересного… форма + вывод полученных данных…

Вас может еще заинтересовать список тем : #PHP | #PHP_FUNCTION | #SEARCH | #PHP_BOOK | Последняя дата редактирования : 2020-07-01 08:23 https://dwweb.ru/comments_1_5/include/img/hand_no_foto.png no no   BBcode

Example

How to set SERP API key


The SerpApi api_key can be set globally using a singleton pattern.

$client = new GoogleSearch();
$client->set_serp_api_key("Your Private Key");

Or

$client = new GoogleSearch("Your Private Key");

Search API capability

$query = ;

$client = new GoogleSearch("private key");

$html_results = $client->get_html($query);
$json_results = $client->get_json($query);

Location API

$client = new GoogleSearch($this->API_KEY);
$location_list = $client->get_location('Austin', 3);
print_r($location_list);

it prints the first 3 location matching Austin (Texas, Texas, Rochester)

,
  :keys=>},
  ...]

Search Archive API

Let’s run a search to get a search_id.

$client = new GoogleSearch($this->API_KEY);
$result = $client->get_json($this->QUERY);
$search_id = $result->search_metadata->id

Now let’s retrieve the previous search from the archive.

$archived_result = $client->get_search_archive($search_id);
print_r($archived_result);

it prints the search from the archive.

Account API

$client = new GoogleSearch($this->API_KEY);
$info = $client->get_account();
print_r($info);

it prints your account information.

Search Google Images

$client = new GoogleSearch($this->API_KEY);
$data = $client->get_json();

foreach($data->images_results as $image_result) {
  print_r($image_result->original);
  //to download the image:
  // `wget #{image_result}`
}

this code prints all the images links, and download image if you un-comment the line with wget (linux/osx tool to download image).

Поиск по контенту сайта -> база данных

Для данного примера есть архив

04.05.2020Друзья!

Я уже давно не занимался базами данных, поэтому, никак проверить не смогу работоспособность данного скрипта!

поиск по базе данных сайта.

Нам понадобится:

Берем скрипт вывода из базы данных

Все что внутри цикла while удаляем и туда вставляем:

if(@substr_count($row, $poisk) and $poisk) { $line_count ++; $rezult .= ‘<a href =»‘.$row.'» target=»_blank»>’.$row.'</a>’ ; }

Где :

1). $row — столбец, отвечающий за контент 2). $row — столбец, отвечающий за ссылку 3). $row — столбец, отвечающий за заголовок

Ниже скрипта располагаем форму для отправки запроса на поиск оп базе данных:

<form method=»POST» action=»»> <input type=»text» name=»poisk»> <input type=»submit» name=»button» value=»ОТПРАВИТЬ»> </form>

В самом верху страницы располагаем функцию собственную функцию strtolower

function my_strtolower($str) { $ru_array = array(‘А’ => ‘а’,’Б’ => ‘б’,’В’ => ‘в’,’Г’ => ‘г’,’Д’ => ‘д’, ‘Е’ => ‘е’,’Ё’ => ‘ё’,’Й’ => ‘й’,’Ж’ => ‘ж’,’З’ => ‘з’,’И’ => ‘и’,’К’ => ‘к’,’Л’ => ‘л’,’М’ => ‘м’,’Н’ => ‘н’,’О’ => ‘о’,’П’ => ‘п’,’Р’ => ‘р’,’С’ => ‘с’,’Т’ => ‘т’,’У’ => ‘у’,’Ф’ => ‘ф’,’Х’ => ‘х’,’Ц’ => ‘ц’,’Ч’ => ‘ч’,’Ш’ => ‘ш’,’Щ’ => ‘щ’,’Ъ’ => ‘ъ’,’Ы’ => ‘ы’,’Ь’ => ‘ь’,’Э’ => ‘э’,’Ю’ => ‘ю’,’Я’ => ‘я’); return strtr($str,$ru_array ); }

Следующей строкой получаем данные из формы :

if($_POST){ $poisk = strip_tags ( $_POST );}

Пропускам данные через my_strtolower:

$poisk = my_strtolower( $poisk );

Custom Tokenizer

First, create your own Tokenizer class that implements TokenizerInterface:

use TeamTNT\TNTSearch\Support\TokenizerInterface;

class SomeTokenizer implements TokenizerInterface {

    public function tokenize($text) {
        return preg_split("/+/u", strtolower($text), -1, PREG_SPLIT_NO_EMPTY);
    }
}

The only difference here from the original is that the regex contains a dash

After you have the tokenizer ready, your and class should consume it.

$someTokenizer = new SomeTokenizer;

$indexer = new TNTIndexer;
$indexer->setTokenizer($someTokenizer);

And in the class you do the same

$someTokenizer = new SomeTokenizer;

$tnt = new TNTSearch;
$tnt->setTokenizer($someTokenizer);

Механизм работы

Функция PHP array_search() поочередно сравнивает value со всеми значениями в массиве collection. По умолчанию, сравнение осуществляется без учета типов операндов. Эту настройку можно изменить, установив для флага strict значение TRUE. Сравнение строк осуществляется с учетом регистра.

При обнаружении совпадения возвращается ключ, соответствующий найденному элементу, и работа функции прекращается. Следовательно, с ее помощью нельзя обнаружить множественное вхождение искомого значения в массив.

Если совпадений не найдено, функция вернет булево значение FALSE.

Проверять возвращенный результат следует с помощью оператора строгого равенства (===)

Это важно, так как функция может вернуть значение, которое приводится к FALSE, например, 0 или пустую строку

Что еще — небольшой бонус трек, вместо заключения

С момента публикации предыдущей статьи в Reindexer-е появилось много новых возможностей. Самая главная из них — полноценный серверный (standalone) режим работы.

golang API в серверном режиме, полностью совместимо с API в embeded режиме. Любые существующее приложения можно перевести с embeded на standalone заменой одной строчки.

Вот так приложение будет работать в embeded режиме, сохраняя данные на локальной файловой системе в папке

Вот так приложение будет работать с standalone сервером, по сети:

Standalone сервер можно либо установить с dockerhub, либо

И еще, мы открыли телеграмм официальный канал поддержки Reindexer. Если есть вопросы или предложения — добро пожаловать!

Описание

array_search

Ищет в haystack значение needle и возвращает ключ, если таковое присутствует в массиве, FALSE в противном случае.

Если вы передадите значение TRUE в качестве необязательного третьего параметра strict , функция array_search() также проверит тип needle в массиве haystack .

Если needle присутствует в haystack более одного раза, будет возвращён первый найденный ключ. Для того, чтобы возвратить ключи для всех найденных значений, используйте функцию array_keys() с необязательным параметром search_value .

Пример 1. Пример использования array_search()

<?php $array = array(0 => «blue» , 1 => «red» , 2 => 0x000000 , 3 => «green» , 4 => «red» );$key = array_search («red» , $array ); // $key = 1;$key = array_search («green» , $array ); // $key = 2; (0x000000 == 0 == «green»)$key = array_search («green» , $array , true ); // $key = 3;?>

Внимание

Эта функция может возвращать как логическое значение FALSE , так и не относящееся к логическому типу значение, которое приводится к FALSE , например, 0 или «». За более подробной информации обратитесь к разделу Булев тип

Используйте оператор === для проверки значения, возвращаемого этой функцией.

Другие решения

Если вы используете (PHP 5> = 5.5.0), вам не нужно писать собственную функцию для этого, просто напишите эту строку, и все готово.

Если вы хотите только один результат:

Для нескольких результатов


Если вы используете PHP < 5.5.0, вы можете использовать этот бэкпорт, спасибо Рэмси!

Обновление: я делал несколько простых тестов, и форма с несколькими результатами, кажется, самая быстрая, даже быстрее, чем пользовательская функция Jakub!

236

Я знаю, что на этот вопрос уже был дан ответ, но я использовал его и немного расширил в своем коде, чтобы у вас не было поиска только по uid. Я просто хочу поделиться им с кем-то, кому может понадобиться эта функциональность.

Вот мой пример и, пожалуйста, помните, что это мой первый ответ. Я вынул массив param, потому что мне нужно было искать только один конкретный массив, но вы могли легко добавить его. Я хотел по сути искать больше, чем просто uid.

Кроме того, в моей ситуации может быть несколько ключей для возврата в результате поиска по другим полям, которые могут быть не уникальными.

Позже я закончил писать это, чтобы позволить мне искать другое значение и ассоциативный ключ. Итак, мой первый пример позволяет вам искать значение в любом конкретном ассоциативном ключе и возвращать все совпадения.

Этот второй пример показывает, где в определенном ассоциативном ключе (first_name) найдено значение (‘Taylor’) А ТАКЖЕ другое значение (true) находится в другом ассоциативном ключе (используется) и возвращает все совпадения (ключи, в которых работают люди с именем «Тейлор» И).

Использование функции

Результат

15

Я модифицировал один из примеров ниже описания функции array_search. функция вернуть все значения по $ key из многомерного массива (N уровней). Возможно, это было бы полезно для кого-то. Пример:

Код функции:

8

В более поздних версиях PHP (> = 5.5.0) вы можете использовать эту строку:

7

Видать array_filter будет подходящим решением для этого …

Код PHP

4

Несмотря на то, что это старый вопрос, на который есть принятый ответ, я подумал, что могу предложить одно изменение в принятом ответе. Итак, во-первых, я согласен, что принятый ответ здесь верен.

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

3

Получение и загрузка данных

Для удобства отладки, мы разделили процесс получения/парсинга данных с Хабра и загрузку их в реиндексер на два отдельных этапа:

Парсим Хабр

За загрузку и парсинг страничек Хабра отвечает функция — ее задача скачать с Хабра статью с указанным ID, распарсить полученную html страничку, а так же загрузить первую картинку из статьи и сделать из нее thumbinail.

Результат работы функции — заполненная структура со всеми полями, включая комментарии к статье и массив с картинкой.

Как устроен парсер, можно посмотреть на

В режиме импорта данных приложение вызывает в цикле с ID от 1 до 360000 в несколько потоков, а результаты сохраняет в набор json и jpg файлов.

При скачивании в 5 потоков — весь Хабр скачивается примерно за ~8 часов. Из возможных 360000 статей — корректные статьи есть только по 170000 ID-шникам, по остальным ID возвращается та или иная ошибка.

Суммарный объем распарсенных данных — около 5gb.

Загружаем данные в Reindexer

После завершения импорта Хабра у нас есть 170к json файлов. За загрузку сета файлов в Reindexer отвечает функция

Эта функция преобразует каждый сохранённый JSON в структуру HabrPost и загружает ее таблички и

Обратите внимание, комментарии выделены в отдельную табличку, чтобы была возможность поиска по отдельным комментариям

Можно бы поступить по другому и хранить все в одной таблице (это, кстати, уменьшило бы размер индекса в памяти), но тогда бы не было возможность поиска отдельных комментариев.

Эта операция не очень долгая — на загрузку всех данных в Reindexer уходит примерно 5-10 минут, в один поток.

Настройка полнотекстового индекса

У полнотекстового индекса есть целый набор настроек. Эти настройки вместе с настройками из DSL напрямую определяют качество поиска.

В настройки входит:

  • список «стоп слов»: это слова, которые часто употребляются в документах и не несут никакой смысловой нагрузки.
  • опции построения индекса: поддержка транслита/опечатки/неверная раскладка клавиатуры
  • коэффициенты формулы вычисления релевантности. В нее входят: функция bm25, дистанция между найденными словами, длина слова из запроса, признаки точного/не точного совпадения.

В нашем приложении за установку параметров поиска отвечает функция репозитория

Про фронтенд и баг Chrome с «бесконечным» скролом

Фронтенд реализован на vue.js — https://github.com/igtulm/reindex-search-ui


Когда делали «бесконечный» скрол с подгрузкой результатов столкнулись с очень неприятным багом Google Chrome — по мнению последнего, загрузка ответа от сервера при скроле иногда занимает 3-4 секунды.

Как так! У нас же быстрый бэкенд с реиндексером, отвечающий за миллисекунды -а тут, целых 4 секунды. Стали разбираться:

По логам сервера все хорошо — ответы отдаются за считанные миллисекунды.

Логи сервера, конечно, не истина в последней инстанции. Поэтому, посмотрел на трафик tcpdump-ом. И tcpdump тоже подтвердил, что сервер отвечает за миллисекунды.

Попробовали в Safari и Firefox — в них такой проблемы нет. Следовательно, проблема явно не во времени ответа бэкенда, а где то еще.

Кажется, проблема все же в Chrome.

Несколько часов гугления принесли плоды — на stackoverflow есть статья с workaround

И добавление магического «workaround» из статьи отчасти исправило проблему в Chrome:

Однако, все равно, если очень-очень активно скролить тачпадом, изредка, возникает задержка.

Quick start

$ composer require serpapi/google-search-results-php

Then you need to load the dependency in your script.

if not, you must clone this repository and link the class.

require 'path/to/google-search-results';
require 'path/to/restclient';

Then you can start coding something like:

$client = new GoogleSearch("your secret key");
$query = ;
$response = $client->get_json($query);
print_r($json_results)

This example runs a search about «coffee» using your secret api key.

The SerpApi service (backend)

  • searches on Google using the query: q = «coffee»
  • parses the messy HTML responses
  • return a standardizes JSON response The Php class GoogleSearch
  • Format the request to SerpApi server
  • Execute GET http request
  • Parse JSON into Ruby Hash using JSON standard library provided by Ruby Et voila..

Alternatively, you can search:

  • Bing using BingSearch class
  • Baidu using BaiduSearch class
  • Ebay using EbaySearch class
  • Yahoo using YahooSearch class
  • Yandex using YandexSearch class
  • Walmart using WalmartSearch class
  • Youtube using YoutubeSearch class

Поиск по контенту сайта -> файлы DW — search 1.2

04.05.2020

Пример на отдельной странице.

Скачать со страницы

Описание обновлено!

Если мы говорим о поиске по контенту на сайте, который сделан на файлах, то первое с чем мы сталкиваемся, против базы данных, как получить все ссылки на все файлы!?

Другими словами, где у вас есть все ссылки вашего сайта!?sitemap.XML Теперь не нужно$domen = $_SERVER.’://’.$_SERVER ; 1).file_get_contents$ALL_pages = file_get_contents(‘https://dwweb.ru/sitemap.xml’); 2).locpreg_match_allpreg_match_all(«#<loc>(.+?)</loc>#i», $ALL_pages, $url); 3).удалить$fruit = array_shift($url); 4).путь до корневой

+ Получим в переменную $poisk от правленный поисковый запрос.

+ все буквы приведем к нижнему регистру my_strtolower

$home = $_SERVER;

if($_POST){ $poisk = strip_tags ( $_POST );}

$poisk = my_strtolower( $poisk );

5).

if($_POST)

{

if( $poisk )

{

for ($i = 0; $i < count($ALL_PAGES); $i++)

{

if( file_exists( str_replace( $domen , $home , $ALL_PAGES) ) )

{

6).

Теперь весь контент страницы полученный в цикле через file_get_contents переведем в нижний регистр — my_strtolower и внутри получим путь на сревре заменив домен на $home

substr_count

+ если что-то найдено, то создаем счетчик +1($line_count)

+ заносим в переменную $rezult адрес страницы, где это было найдено.

$new = my_strtolower( file_get_contents( str_replace( $domen , $home , $ALL_PAGES) ) );

if (substr_count($new, $poisk))

{

$line_count += 1;

$rezult .= ‘<a href =»‘.$ALL_PAGES.'» target=»_blank»>’.$ALL_PAGES.'</a><br>’ ;

7).if($line_count)($vivod_info) 8).$rezult = ‘Отправлен пустой запрос’;

Далее особо ничего интересного… форма + вывод полученных данных…

Бэкенд

Структура и используемые компоненты

Бэкенд — это golang приложение. В качестве http сервера и роутера используются fasthttp и fasthttprouter. В данном конкретном случае, можно было бы использовать любой другой набор сервера и роутера, но решил остановиться на них. В качестве БД используется reindexer, а для парсинга html страниц — замечательная библиотечка goquery

Структура приложения очень простая и состоит всего из 4-ех модулей:

  • Репозиторий — отвечает за работу с хранилищем данных, так же в нем описание моделей данных
  • HTTP — отвечает за обработку запросов
  • Парсер — отвечает за парсинг страничек Хабра
  • main — обработка интерфейса командной строки и запуск/инициализации компонентов

Методы API

  • /api/search – полнотекстовый поиск постов и комментариев
  • /api/posts/:id — получение поста по ID
  • /api/posts — получение листинга постов с фильтрацией

Модели данных

Модели данных — это golang структуры. При работе с Reindexer в тэгах полей структуры описываются индексы, которые будут построены по полям.

Остановлюсь на выборе индексов подробнее — от выбора индексов зависит как и скорость выполнения запросов, так и потребляемая память.

Поэтому очень важно назначить правильные индексы полям, по которым предполагается поиск или фильтрация. Структура с постом:

Структура с постом:

Структура с комментария заметно проще, поэтому не будем на ней останавливаться.

Метод транспозиции

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

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647

#define _CRT_SECURE_NO_WARNINGS // для корректной работы scanf()#include <stdio.h>#include <stdlib.h>    // для переключения на русский язык — функция system()// Функция поиска в массиве k размерности n// элемента со значением key с использованием транспозицииint search(int *k, int n, int key){  int temp;          // вспомогательная переменная для обмена  for (int i = 0; i<n; i++) // просматриваем все элементы в цикле  {    if (k == key)    // если находим элемент со значением key,    {      if (i == 0)      // если индекс равен нулю, возвращаем его,        return i;     // потому что смещаться ближе к началу массива невозможно      temp = k;      // меняем местами найденный элемент с предыдущим      k = k;      k = temp;      return i;         // возвращаем найденный индекс элемента    }  }  return -1;  // если элемент не найден, возвращаем -1}int main() {  int k;    // описываем массив из 8 элементов  int point;    // индекс элемента, равного указанному значению (3)  system(«chcp 1251»); // переходим на страницу 1251 для поддержки русского языка  system(«cls»);       // очищаем окно консоли  // В цикле вводим элементы массива  for (int i = 0; i<8; i++)  {    printf(«Введите k: «, i);    scanf(«%d», &k);  }  // Повторяем процедуру поиска 6 раз (с учетом транспозиции)  for (int j = 0; j < 6; j++)   {    point = search(k, 8, 3); // вызов функции поиска    // Вывод индекса элемента, равного 3    if (point == -1)      printf(«Элементов равных 3 в массиве нет!\n»);    else      printf(«Элемент с индексом %d равен 3\n», point);  }  getchar(); getchar();  return 0;}


С этим читают