Поиск не находит определённую комбинацию символов

#1 25 сентября 2019 в 11:54
Здравствуйте, уважаемые!
Вторая ветка. Проблема наблюдается на разных ветках (на 2.11 и 2.12.2 — точно).
Столкнулся со странной проблемой в поиске: не ищется определённая комбинация символов: "111-11" (три символа тире два символа).
Если ввести в поле поиска именно "111-11", результат — "Ничего не найдено".
В заголовках записей такая комбинация, естественно, присутствует, какие именно цифры или буквы в запросе значения не имеет.
Второй день мучаю модель, найти разгадку не могу. cry
Помогите, кто чем может!
Заранее благодарен!
#2 25 сентября 2019 в 12:25
Олег Васильевич я,
В каком поле ищем? Проставлено ли для этого поля "Участвует в полнотекстовом поиске"?
#3 25 сентября 2019 в 13:00
Такое давно наблюдается. Например на демо сайте если искать фразу «все больше россиян», то всё хорошо ищет, а если фразу «все больше» или «все хорошо», то выдает ошибку "Слишком короткие слова в запросе".
А вот, например, если ввести фразу «все норма», то правильно пишет "ничего не найдено"
#4 25 сентября 2019 в 14:28

если фразу «все больше» или «все хорошо», то выдает ошибку "Слишком короткие слова в запросе".

islyaeFF
Оно не пропускает к участию в поиске стоп-слова, которые как правило, не несут смысловой нагрузки.
Смотрите файл \system\languages\ru\stopwords\stopwords.php
#5 25 сентября 2019 в 18:24

В каком поле ищем? Проставлено ли для этого поля "Участвует в полнотекстовом поиске"?

Ris
Демо-сайт системы, тип контента "Новости", поля:
Тип поля "Заголовок" участвует в поиске по умолчанию (если тип контента активирован в опциях компонента "Поиск" ("птичка" в опциях присутствует));
в поле "Текст новости" (тип поля "Текст HTML") опция активирована:
Новость с искомым значением: joxi.ru/krD7Y31sK3NYeA
Ищем значенние: joxi.ru/DrlEZq7UVJaoam
Как писал выше, проверял на разных версиях системы (в т.ч. на текущей), добавлю: на разных версиях РНР, на разных хостах, в разных браузерах
#6 25 сентября 2019 в 20:09
Олег Васильевич я,
У меня ищет нормально.
Может дело не в бобине, а где-то в версии mysql?
#7 25 сентября 2019 в 20:52

Может дело не в бобине, а где-то в версии mysql ?

Ris
У меня на локальном: MySQL — 5.5, двиг — InnoDB. Похоже, от двига не зависит (менял на MyISAM)), от РНР тоже (юзал 5.6.3, 5.6.4 и 7.2.22-he.0)
Да и тестировалось и на разных сайтах, и серверах, и версиях РНР
#8 25 сентября 2019 в 21:05
Кстати, в фильтре записи по такому запросу фильтруются без проблем.
#9 25 сентября 2019 в 21:24
Олег Васильевич я,
Проверил на тестовом сайте и на локальном.
На локальном всё работает при любых версиях мускула и пыхапе, на тестовом не работает ни при каких условиях.
#10 25 сентября 2019 в 21:49
Беда бедовая cry
Ris, спасибо!
#11 25 сентября 2019 в 22:04
Олег Васильевич я,
Проверил print_r($word); слово, которое отправляется в поиск.
И на локальном и на тестовом результат один: 111-
На локальном находит всё. Запрос mysql:
  1. SELECT `id`, `slug`, `date_pub`, `title`, `photo`, MATCH(`title`) AGAINST ('>\"111-11\" <(+111-*)' IN BOOLEAN MODE) AS fsort
  2. FROM cms_con_news
  3. WHERE `is_pub` = '1' AND `is_approved` = '1' AND `is_deleted` IS NULL AND `is_parent_hidden` IS NULL AND MATCH(`title`) AGAINST ('>\"111-11\" <(+111-*)' IN BOOLEAN MODE)
  4. ORDER BY fsort DESC
  5. LIMIT 0, 15
находит одну строку
На тестовом сайте на реальном VPS на весте:
111-
  1. SELECT `id`, `slug`, `date_pub`, `title`, `photo`, MATCH(`title`) AGAINST ('>\"111-11\" <(+111-*)' IN BOOLEAN MODE) AS fsort
  2. FROM cms_con_news
  3. WHERE `is_pub` = '1' AND `is_approved` = '1' AND `is_deleted` IS NULL AND `is_parent_hidden` IS NULL AND MATCH(`title`) AGAINST ('>\"111-11\" <(+111-*)' IN BOOLEAN MODE)
  4. ORDER BY fsort DESC
  5. LIMIT 0, 15
Находит 0 строк.
#12 25 сентября 2019 в 23:07

Проверил print_r($word); слово, которое отправляется в поиск.
И на локальном и на тестовом результат один: 111-

Ris
В поиск отправляется 111- вместо 111-11 потому что в модели компонента строка укорачивается на 2 символа:
  1.  
  2. } else if (mb_strlen($word) >= 6) {
  3. $word = mb_substr($word, 0, mb_strlen($word) - 2);
  4.  
Убирал, толку ноль.
#13 28 сентября 2019 в 01:18
Похоже, сразу несколько недочётов в классе modelSearch.
Первый — свойство $three_symbol_search. Если значение по умолчанию выставить в true, начинает искаться. Правда, возникают иные проблемы, но разберёмся…
#14 28 сентября 2019 в 15:51
Как оказалось, проблема несколько шире:
1. также не ищутся последовательности содержащие апостроф и двоеточие (дальше этих знаков экспериментировать не стал)
2. возникает в достаточно коротких запросах (одно слово, количество знаков до 6 включительно)
3. проблемный символ может быть в любой позиции строки до 3 включительно (от ноля считаем)
Ламерское решение под спойлером. Изменён 1 файл: system\controllers\search\model.php (код актуален для текущей версии из github).
Там всё откомментировано. Уважаемые гуру, помогите дожать "до коробки"!

  1.  
  2. <?php
  3.  
  4. class modelSearch extends cmsModel{
  5.  
  6. protected $query;
  7. protected $original_query;
  8. protected $type;
  9. protected $date_interval;
  10. protected $three_symbol_search = false;
  11. protected $punctuation_mark = false;//OV:: не будем лезть куда не следует
  12.  
  13. public function setQuery($query){
  14.  
  15. $query = strip_tags(mb_strtolower(trim(urldecode($query))));
  16.  
  17. $this->original_query = $query;
  18.  
  19. $this->query = array();
  20.  
  21. $stopwords = string_get_stopwords(cmsCore::getLanguageName());
  22.  
  23. if (mb_strlen($query) == 3) {
  24.  
  25. if(!$stopwords || ($stopwords && !in_array($query, $stopwords))){
  26.  
  27. $this->three_symbol_search = true;
  28.  
  29. $this->query[] = $query;
  30.  
  31. return true;
  32.  
  33. }
  34.  
  35. return false;
  36.  
  37. }
  38.  
  39. $words = explode(' ', $query);
  40.  
  41. if (array_key_exists('1', $words) == false) { //OV:: запрос из одного слова
  42. $punctuation_in_word = preg_match('(^A-Za-z0-9)', $words[0]);//OV:: ищем в запросе "не буквы и не цифры"
  43.  
  44. //OV:: запрос должен быть коротким и содержать "не буквы и не цифры"
  45. if (mb_strlen($words[0]) <= 6 && $punctuation_in_word !== false) {
  46. $this->punctuation_mark = true;
  47. }
  48.  
  49. }
  50.  
  51. foreach($words as $word){
  52.  
  53. if (mb_strlen($word)<3) { continue; }
  54. if($stopwords && in_array($word, $stopwords)){ continue; }
  55. if (mb_strlen($word)==3) { $this->query[] = $this->db->escape($word); continue; }
  56.  
  57. if($this->punctuation_mark) {//OV:: запрос, попадающий под условие, не укорачиваем (хотя работает)
  58.  
  59. if (mb_strlen($word) >= 12) {
  60. $word = mb_substr($word, 0, mb_strlen($word) - 4);
  61. } else if (mb_strlen($word) >= 10) {
  62. $word = mb_substr($word, 0, mb_strlen($word) - 3);
  63. } else if (mb_strlen($word) >= 6) {
  64. $word = mb_substr($word, 0, mb_strlen($word) - 2);
  65. } else {
  66. $word = mb_substr($word, 0, mb_strlen($word) - 1);
  67. }
  68.  
  69. }
  70.  
  71. $this->query[] = $this->db->escape($word) . '*';
  72.  
  73. }
  74.  
  75. if (empty($this->query)) { return false; }
  76.  
  77. return true;
  78.  
  79. }
  80.  
  81. public function setSearchType($type){
  82. $this->type = $type;
  83. }
  84.  
  85. public function setDateInterval($date){
  86. $this->date_interval = $date;
  87. }
  88.  
  89. public function getFullTextQuery(){
  90.  
  91. $ft_query = '';
  92.  
  93. switch ($this->type){
  94.  
  95. case 'words':
  96.  
  97. if ($this->three_symbol_search || $this->punctuation_mark) {//OV::
  98.  
  99. $ft_query .= '%'.$this->db->escape($this->original_query).'%';
  100.  
  101. } else {
  102.  
  103. $ft_query .= '>\"' . $this->db->escape($this->original_query).'\" <(';
  104. $ft_query .= '+' . implode(' +', $this->query).')';
  105.  
  106. }
  107.  
  108. break;
  109.  
  110. case 'exact':
  111.  
  112. if ($this->three_symbol_search) {
  113.  
  114. $ft_query .= $this->db->escape($this->original_query);
  115. //OV::
  116. } elseif($this->punctuation_mark) {
  117.  
  118. $ft_query .= '%'.$this->db->escape($this->original_query).'%';//OV:: а здесь не верный запрос, но без '%' ничего не находит
  119. //OV:: end
  120. } else {
  121.  
  122. $ft_query .= '\"' . $this->db->escape($this->original_query) . '\"';
  123.  
  124. }
  125.  
  126. break;
  127.  
  128. }
  129.  
  130. return $ft_query;
  131.  
  132. }
  133.  
  134. public function getSearchSQL($table_name, $match_fields, $select_fields, $filters){
  135.  
  136. $match_fields = '`'.implode('`, `', $match_fields).'`';
  137. $select_fields = array_map(function($v){
  138. if(is_numeric($v)){
  139. return $v;
  140. }
  141. return '`'.$v.'`';
  142. }, $select_fields);
  143. $select_fields = implode(', ', $select_fields);
  144.  
  145. $query = $this->getFullTextQuery();
  146.  
  147. $filter_sql = '';
  148.  
  149. if ($this->date_interval != 'all'){
  150.  
  151. switch ($this->date_interval){
  152. case 'w':
  153. $filter_sql .= "DATEDIFF(NOW(), date_pub) <= 7 AND ";
  154. break;
  155. case 'm':
  156. $filter_sql .= "DATE_SUB(NOW(), INTERVAL 1 MONTH) < date_pub AND ";
  157. break;
  158. case 'y':
  159. $filter_sql .= "DATE_SUB(NOW(), INTERVAL 1 YEAR) < date_pub AND ";
  160. break;
  161. }
  162.  
  163. }
  164.  
  165. if($filters){
  166. $_filter_sql = array();
  167. foreach (
#15 28 сентября 2019 в 21:09
Олег Васильевич я,
Повторюсь, у меня на локальном опенсервере всё нормально ищет, а на тестовом VPS под управлением весты не искало.
Решил проанализировать. Нашел отличие в конфиге mysql.
Переменная ft min word len на опенсервере — 3, а на тестовом — 4.
Изменил переменную (прописал в my.cnf ft_min_word_len=3 ). Теперь всё нормально ищет.
Выслал в личку доступ к тестовому сайту для экспериментов.
Вы не можете отвечать в этой теме.
Войдите или зарегистрируйтесь, чтобы писать на форуме.
Используя этот сайт, вы соглашаетесь с тем, что мы используем файлы cookie.