Javascript-форум (https://javascript.ru/forum/)
-   Элементы интерфейса (https://javascript.ru/forum/dom-window/)
-   -   Помогите подправить поиск на сайте (https://javascript.ru/forum/dom-window/76592-pomogite-podpravit-poisk-na-sajjte.html)

Alexko64 28.01.2019 11:02

Поставте себя на место пользователя. Вы ищете Note 6, а вам выдает Note 4 6GB, вы ведь его не искали, зачем он вам?
Вы-же не бутеде писать пользователю "Друг, вы искали Note 6, а мы вам показываем Note 4 6GB потому-что 6 есть в 6GB.

Я пришел к мысли что с конструкцией SLS.isearch.on('keyup',function(){ не возможно резлизовать точный поиск, если-бы я мог его сделать сам, то сделал бы так:
Убрал-бы isearch.on('keyup',function(){ и добавил-бы кнопку "поиск". Поиск-бы начинал после ее нажатия и искал-бы точное вхождение всех слов из поисковой строки, не учитывая порядок, при этом искал жесткое вхождение, где 6 это целое слово и оно не имеет отношения к 6GB

Мне кажется такой вариант будет давать оптимальный результат. Это мое ИМХО

P.S. Задача вебмастера будет структурировать все данные по одному шаблону, что-бы было всегда 6GB, а не 6 GB. А задача пользователя искать конкретные вещи, Note 6 если ему пофиг на GB, Note 6GB если ему пофиг какой Note, главное что-бы Note и 6GB ili Note 6 6GB, если нужен i Note и 6 и 6GB

Alexko64 28.01.2019 11:07

Цитата:

Сообщение от рони (Сообщение 502755)
Alexko64,
function escapeRegExp(string){
    return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}

function fnSearch(arr, pattern) {
    return arr.filter(function(product) {
             var text = $("<div/>", {html : product.html}).text().toLowerCase();
        return pattern
            .trim()
            .toLowerCase()
            .split(/\s+/)
            .every(function(p) {
                p = escapeRegExp(p);
                p = new RegExp("(^|\\s)"  + p, "i");
                return p.test(text)
            });
    });
}


Кстати, вариант с отрезанием хтмл тегов тормозит на большом количестве товаров, вот тут пример
http://mobidor.zzz.com.ua/test2.php

А вариант без обрезания хтмл тегов работает как пуля с тем-же количеством товаров
http://mobidor.zzz.com.ua/test.php
но поиск не коректный, из за тегов

laimas 28.01.2019 12:57

Цитата:

Сообщение от Alexko64
Поставте себя на место пользователя. Вы ищете Note 6, а вам выдает Note 4 6GB, вы ведь его не искали, зачем он вам?

А с чего такая уверенность что я буду именно так искать? :) Я могу искать среди всех по каким то критериям, например по размеру ROM, а потом уже среди них выбирать. Вы когда поисковиком пользуетесь, он же вам не выдает одну страницу найденную, а все те, в которых было найдено.

А конструировать "было всегда 6GB, а не 6 GB" по уму должен программист создавая базу, а в ней параметры уж точно никогда не держат в виде 6 GB или 6GB, содержат именно 6, и каждую важную характеристику в отдельном поле, а никак не все одной строкой. Именно это и позволяет делать фильтрованные запросы, а поиск по совпадению, это уже полнотекстовый поиск, для которого все поля характеристик будут иметь составной индекс FULLTEXT. Вот нечто подобное должно быть и на клиенте реализовано, если по каким либо причинам этим не занимается сервер.

Alexko64 28.01.2019 13:47

Пример поисковика не уместен и не спрашивайте почему если это и так не ясно.

Тоисть для вас нормально искать 5, а найти 50, 500, 5000? Разве вы не понимаете что это разные вещи?

laimas 28.01.2019 13:57

Цитата:

Сообщение от Alexko64
Тоисть для вас нормально искать 5, а найти 50, 500, 5000? Разве вы не понимаете что это разные вещи?

Мы вообще не можем знать, чего хочет пользователь. Например, я хочу найти модели с определенным объемом ROM, не важно чьи, вот хочу подобрать по этому параметру, и вводить могу как как 64 ROM, 64G ROM, ROM 64 и т.п. Это ведь не запрещено ни чем? Именно так я и буду искать в поисковике - смартфон + объем памяти, так что все уместно, ибо он будут искать релевантный текст, в котором есть 64 и ROM.

А у вас весь поиск в строке и что бы вы не делали подгадать под все варианты ввода пользователем не получится.

Alexko64 28.01.2019 14:15

Ага, вы еще 4G RАM введите и понадейтесь найти телефоны с памятью 4ГБ, оно выдаст вам все телефоны 4G сети и радуйтесь. Ладно, мы с вами мыслим по разному.
Да, вы путаете фильтр с поиском, кстати. Это разные вещи.

Цитата:

Сообщение от laimas (Сообщение 502820)
А у вас весь поиск в строке и что бы вы не делали подгадать под все варианты ввода пользователем не получится.

Пусть пользователи подстраиваются под формат данных на сайте, а не наоборот. Это моя позиция

laimas 28.01.2019 14:32

Цитата:

Сообщение от Alexko64
Ага, вы еще 4G RАM введите и понадейтесь найти телефоны с памятью 4ГБ, оно выдаст вам все телефоны 4G сети и радуйтесь.

А почему бы и нет? Я могу подбирать как по объему RAM, так и ROM. А как еще ищут варианты, сразу конкретно? Это ведь поиск, я волен поступать так как хочу. Проблема не в этом, а в том что вводится.

Пользователя "подстроить под форму" конечно можно, пока он методом научного тыка не поймет все ваши правила, но так тоже не делается, вернее это плохо, когда непонятно.

Цитата:

Сообщение от Alexko64
Это моя позиция

Да мне то все равно, хозяин барин, я лишь высказываю мнение. ;)

Malleys 29.01.2019 14:32

Описание на данный момент занимает 351КБ места (то, которое у вас), и в основном содержит повторяющиеся HTML-элементы. Храните только сами данные, без того, как они должны быть представлены. Данные в чистом виде легко обрабатывать, чем пытаться их вытащить из разметки! (jQuery с этим ужасно не справляется, для этого лучше подходит класс DOMParser, он для такого и предназначен)

Но всё-таки вот вариант с DOMParser...
function fnSearch(array, pattern) {
	var parts = pattern.trim().toLowerCase().split(/\s+/);
	var p = new DOMParser();
	var s = Symbol.for("product description");
	
	return array.filter(function(product) {
		var description =
			s in product ?
			product[s] :
			product[s] =
				p	.parseFromString(product.html, "text/html")
					.body
					.textContent
					.toLowerCase()
					.split(/\s+/)
			;
		
		return parts.every(function(part) {
			return description.some(function(word) {
//					return word === part;
				return word.startsWith(part);
			});
		});
	});
}

Оно ищет так, чтобы каждое искомое слово в описании начиналось на него! Если вам нужно, что каждое искомое слово присутствовало полностью в описании, то используйте return word === part;. Я вам рекомендую использовать вариант (word.startsWith(part)), поскольку набрав только "nok" уже видно, что есть "nokia". Однако точное совпадение (word === part) предполагает, что пользователи полностью наберут "nokia", чтобы увидеть результаты "nokia". На самом же деле набрав только "nok", и увидев, что там ничего не появилось, пользователи скорей решат, что там нет того, о чём они думают, чем полностью будут вводить труднопроизносимые для них слова. Вариант (word.startsWith(part)) более интерактивный и подразумевает меньше усилии для достижения результата со стороны пользователя!

И ещё, если ничего не ввести, то (word === part) ничего не покажет, а (word.startsWith(part)) показывает всё! Поэтому вам нужна пошаговая *загрузка*, т. е., например показывайте первые 12 результатов, а остальные добавляются, например, при нажатии на кнопку в конце списка!

Если можно ничего не вводить и получать результаты, то можно добавить, например, ценовой фильтр. (Возможности безграничны!)

Цитата:

Сообщение от Alexko64
не возможно реализовать точный поиск

Вы можете комбинировать (word === part) и (word.startsWith(part)) и пусть пользователь сам выбирает, какой ему нужен поиск! (в примере ниже я показываю, как это сделать)

Также из вашего HTML можно извлечь чистые данные. Данные в чистом виде легко обрабатывать, чем пытаться их вытащить из разметки!
Получается 216КБ после замены на JSON без лишних пробелов и разметки (только чистые данные), что в свою очередь в за-gzip-ированном виде занимает 28КБ.

И уже на основе такого чистого JSON легко генерировать какую угодно разметку! Тогда не нужно использовать даже DOMParser!

Тогда эта функция поиска выглядит так...
function fnSearch(array, pattern) {
	var parts = pattern.trim().toLowerCase().split(/\s+/);

	return array.filter(function({ product }) {
		var description = product.toLowerCase().split(/\s+/);

		return parts.every(function(part) {
			return description.some(function(word) {
				// return word === part;
				return word.startsWith(part);
			});
		});
	});
}


Вот для примера перевёл ваши данные в чистый JSON, и написал маленькую функцию performSearch, которая запускает fnSearch и печатает результат...

Сам пример https://codesandbox.io/s/nnkw1q7rvm?view=preview и код в песочнице
<iframe src="https://codesandbox.io/embed/nnkw1q7rvm?view=preview" style="width:100%; height:700px; border:0; border-radius: 4px; overflow:hidden;" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>


Пользователи вам не роботы извергающие точные запросы! Так что они вам туда ещё напишут "айфон" и "xaomi", так что вы можете улучшить свою программу, добавив... (подсказка: транслитерация, расстояние Левенштейна)

Alexko64 30.01.2019 00:29

Крутая реализация.
Огромное спасибо


Часовой пояс GMT +3, время: 12:06.