В настоящее время у меня есть простая поисковая система на моем сайте
Я пытаюсь соответствовать keyword
во всех областях.
Вот упрощенные рабочие коды
$keyword_search = "Hello World";
$delimeter = ' '; //or your separator
$keywords = explode($delimeter, $keyword_search);
$base_query = \App\Models\EntireSearchSite::where('id','!=',NULL);
foreach($keywords as $keyword){
$base_query->where(function($query) use ($keyword){
$query->where('part_number', 'like', '%' . $keyword . '%')
->orWhere('part_name', 'like', '%' . $keyword . '%')
->orWhere('category', 'like', '%' . $keyword . '%')
->orWhere('description', 'like', '%' . $keyword . '%');
});
}
$data = $base_query->paginate(20);
return $data;
Что я пытаюсь сделать, так это сопоставить все ключевые слова, подсчитать все совпадающие ключевые слова (для каждого вхождения) и выполнить Order By Desc
от самых высоких вхождений к самым низким.
Если я войду "Hello World"
он найдет все данные, которые будут соответствовать "Hello World"
У меня есть part_number, part_name, category, description
поля
он суммирует общее количество вхождений во всех полях и упорядочивает ORDER BY
от самого высокого до самого низкого (DESC)
ПРИМЕР:
ДАННЫЕ №1
количество совпадающих ключевых слов в part_number
равно 0
количество совпадающих ключевых слов в part_name
равно 2
количество совпадающих ключевых слов в category
равно 0
количество совпадающих ключевых слов в description
равно 0
ВСЕГО = 2
ДАННЫЕ #2
количество совпадающих ключевых слов в part_number
равно 0
количество совпадающих ключевых слов в part_name
равно 0
количество совпадающих ключевых слов в category
равно 2
количество совпадающих ключевых слов в description
равно 10
ВСЕГО = 12
ДАННЫЕ №3
количество совпадающих ключевых слов в part_number
равно 0
количество совпадающих ключевых слов в part_name
равно 0
количество совпадающих ключевых слов в category
равно 0
количество совпадающих ключевых слов в description
равно 5
ВСЕГО = 5
и порядок по описанию должен быть примерно таким
ДАННЫЕ №2
ДАННЫЕ №3
ДАННЫЕ №1
ОБНОВЛЯТЬ*
Пробовал ответ от @Anas
$delimeter = ' '; //or your separator
$keywords = explode($delimeter, $keyword_search);
$base_query = \App\Models\EntireSearchSite::where('id','!=',NULL);
foreach($keywords as $keyword){
$base_query->where(function($query) use ($keyword){
$query->where('part_number', 'like', '%' . $keyword . '%')
->orWhere('part_name', 'like', '%' . $keyword . '%')
->orWhere('category', 'like', '%' . $keyword . '%')
->orWhere('description', 'like', '%' . $keyword . '%');
});
}
foreach($keywords as $keyword){
$base_query->selectRaw(function($querySelect) use ($keyword){
$querySelect->selectRaw('
Round ((Char_length(Concat(
part_number,
part_name,
category,
description
)) - Char_length(REPLACE ( Concat(
part_number,
part_name,
category,
description
), "'.$keyword.'", ""))) / Char_length("'.$keyword.'")) AS count
');
});
}
$data = $base_query->orderBy('count','DESC')->paginate(20);
return $data;
Но я получаю неопределенное количество столбцов
Обновлять
Прикладной ответ @Donkarnash
я обновил свой вопрос
Попробуйте объединить связанный столбец в одну строку, а затем получите общее количество вхождений по этому образцу запроса. также вы можете использовать в select DB:raw() Документация Laravel
SELECT email,
name,
Round ((Char_length(Concat(email, name)) - Char_length(REPLACE ( Concat(email,name), "anas", ""))) / Char_length("anas")) AS count
FROM users
Having count >0
ORDER BY count DESC;
Результат запроса
Для отдельного ключевого слова вы можете суммировать новую функцию раунда с другим ключевым словом, проверьте этот запрос.
SELECT email,
name,
Round ((Char_length(Concat(email, name)) - Char_length(REPLACE ( Concat(email,name), "first_keyword", ""))) / Char_length("first_keyword"))
+ Round ((Char_length(Concat(email, name)) - Char_length(REPLACE ( Concat(email,name), "second_keyword", ""))) / Char_length("second_keyword")) AS count
FROM users
Having count >0
ORDER BY count DESC;
Чтобы сделать его нечувствительным к регистру, вы можете преобразовать ключевые слова и столбцы в нижний регистр. Бывший:
SELECT email,
name,
Round ((lower(Char_length(Concat(email, name))) - Char_length(REPLACE ( lower(Concat(email,name)), lower("aasd"), ""))) / Char_length(lower("aasd"))) AS count
FROM users
Having count >0 ORDER BY count DESC;
это хорошо, но ключевое слово не должно быть чувствительным к регистру, независимо от того, написано ли слово с заглавной буквы или нет, если это одно и то же слово. он считает только «анас», но когда я попробовал «анас», он не считает «анас», где он тоже должен считаться.
Я думаю, что я довольно близок, я могу получить данные подсчета на основе вашего кода. Но у меня есть это дополнительное поле, называемое page_content
типом данных TEXT
, где оно содержит некоторый HTML-код. например <p> Lorem sum</p> <h3>Lorem Sum</h3>
, когда я пытался добавить это поле в запрос, запрос, похоже, не работает
В чем ошибка при использовании поля page_content
он не возвращает никаких данных при добавлении поля page_content. это поле иногда содержит некоторое значение html, иногда просто null. возможно, потому что некоторые записи являются нулевыми или, может быть, потому, что он не может подсчитать значение поля, если значение содержит html-коды.
Поскольку в цикле используется selectRaw
, псевдоним операции подсчета не должен быть count
(повторяется для всех итераций цикла). Скорее это должно быть 'count'.$keyword
, чтобы сделать его уникальным псевдонимом.
Точно так же orderBy()
также должен быть определен в цикле, чтобы упорядочивать столбцы 'count'.$keyword
.
$base_query = \App\Models\EntireSearchSite::where('id','!=',NULL);
foreach($keywords as $keyword){
$base_query->where(function($query) use ($keyword){
$query->where('part_number', 'like', '%' . $keyword . '%')
->orWhere('part_name', 'like', '%' . $keyword . '%')
->orWhere('category', 'like', '%' . $keyword . '%')
->orWhere('description', 'like', '%' . $keyword . '%');
});
}
foreach($keywords as $keyword) {
$base_query->selectRaw('
Round (
(Char_length(Concat(email, name)) - Char_length(REPLACE ( Concat(email,name), "' . $keyword .'", ""))
) / Char_length("' . $keyword .'")
) AS count' . $keyword
)
->orderBy("count$keyword", "desc");
}
$data = $base_query->paginate(20);
return $data;
Привет, пытался сделать это, но получил Object of class Closure could not be converted to string
это из-за типа данных моих полей?
Можете ли вы найти в трассировке стека, какая строка кода вызывает ошибку. Потому что я пробовал в соответствии с примером таблицы пользователей @anas, и он безупречно работает с двумя ключевыми словами.
Вероятно, в лог-файле по адресу sotrage/logs/laravel.log
будет подробная запись.
Я обновил свой пост, чтобы увидеть ошибку, у меня есть 10 оставшихся полей, которые я не включил здесь в коды, только part_number, part_name, категория, описание. это необходимо?
проверим это
Обновили ответ, думаю, внешний selectRaw
вызывал ошибку во втором цикле foreach - попробуйте обновленный
Просто для информации, вы можете использовать полнотекстовый поиск и получить оценку в виде процента совпадения - если это служит вашей цели.
@RaeIan «У меня есть 10 оставшихся полей, которые я не включил сюда в коды» - каждый поиск типа «%$term%» снижает производительность, поскольку он не может использовать какой-либо индекс - будьте осторожны. Если у вас есть несколько столбцов для поиска, используя подобную нормализацию оператора в качестве помощи виртуальных столбцов или, что еще лучше, было бы определить полный поисковый индекс с несколькими столбцами в таблице.
Вы можете выбрать все связанные необработанные данные, а затем отсортировать их в своем контроллере.
Обратите внимание, что выполнение сложных запросов занимает много времени. На мой взгляд, вы можете выбрать свои данные, а затем подсчитать совпадающие ключевые слова с помощью функции strpos
.
foreach($i=0;$i<count($data);$i++){
foreach($keywords as $keyword)
{
if (strpos($data[$i]->partition, $keyword) !== false) {
$counter = $counter+1;
.
.
.
.
}
}
$final[$i] = [
'data'=>$data[$i],
'priority'=>$counter
];
}
then you can sort it by ```arsort()``` based on priority
Не совсем то, что вы ищете, но посмотрите на соответствие: w3resource.com/mysql/mysql-full-text-search-functions.php