Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Поменять математику поиска. Вместо поиска словосочетания сделать поиск отдельных слов (https://javascript.ru/forum/misc/38146-pomenyat-matematiku-poiska-vmesto-poiska-slovosochetaniya-sdelat-poisk-otdelnykh-slov.html)

andreydial 21.05.2013 14:11

Поменять математику поиска. Вместо поиска словосочетания сделать поиск отдельных слов
 
Есть сайт (trademosh.com). В нем есть поиск. Если в поле Scool name ... задать словосочетание, то поиски по словосочетанию и будет. По одному слову результаты не выводит. А надо.
Кнопка поиска.
$searchFind_Buut				= <<< TEXT
	 <div id="searchFind_Buut" class="conteiner" >
			 <button id="findLatLon" class="submitButt" onClick="startFind($(this).closest('form'),{$is_mobile});" >Find</button><img id="ajaxLoader" class="ajaxLoader" src="{$LINK_baseUrl}images/ajax-loader_export.gif" alt="data is loading" style="vertical-align:bottom" />
		&nbsp;&nbsp;
		<button id="resetAll" onclick="reset_();" class="submitButt" >Reset</button>
TEXT;

Механизм поиска
Код:

// запрос на поиск по сайту ----------------------------------------------------------------
function startFind(obj,is_mobile)
{
        var searchFild = $("#inputTypeLocation");
        if (allSearchFild.val()==="Scool name, textbook title, keywords") { allSearchFild.val(""); };
        if (searchFild.val()==="Type Location") { searchFild.val(""); };
        var valSF = $.trim(searchFild.val());
        if (valSF==="")
        {
                $("#lonInput").val("");
                $("#latInput").val("");
        }
        var lonFild = $("#lonInput");
        var valLF                = $.trim(lonFild.val());
        var allSearch = $.trim(allSearchFild.val());

        var valDist = $("#maxdistance").val();
        var verNumber= parseFloat(valDist);
        var data = obj.serialize()+"&action=getLonLatID&ID=";

        var data_to_send_search = obj.find("select").not("[disabled]").find("[data_to_send_search]:selected");
        data_to_send_search.each(function(item,elem)
        {
                var obj = $(elem);
                data+="&"+obj.attr("data_to_send_search");
        });

        linkToShow__contact_user.css("color","#FFF");
        ajaxLoader.show();
        findLatLon.hide();
        $.ajax
        ({               
                data: data,               
                success: function(answ)
                {
                    var kml = answ['searchkml'];
                    $('.linkToMap').prop('search', 'q=' + location.protocol + '//' + location.host + '/kml/' + kml);
                    var link = $('.linkToMap').prop('href');
                    $('.map_link_text').text(link);
                        resultLoadData_in_posts(answ);
                }
        });
}

Вроде так. Подскажите где копнуть, хоть намекните :help: Или может я не там ищу.

andreydial 21.05.2013 15:30

var allSearch = $.trim(allSearchFild.val());

Я так думаю здесь формируется слово для запроса?
как преобразовать в отдельные слова фразу с элементом ИЛИ?

animhotep 21.05.2013 15:48

думаю нужно sql-запрос править или как оно там у вас ищет

andreydial 21.05.2013 16:02

//global $Search;
   $ID="";
   $data = array();
   $data["conteinerData"]="";
   $d = (int)$_POST['d'];
   $category	= mysql_real_escape_string($_POST['cat']);
	 $gender		= isset($_POST['gender'])?mysql_real_escape_string($_POST['gender']):null;
	 $category	= $category=="Category"?"":$category;
	 $gender		= $gender=="noGender"?"":$gender;
	 $minPrice	= (float)$_POST['minPrice'];
	 $maxPrice	= (float)$_POST['maxPrice'];
	 $selectSearchDD_emails_edu	= !empty($_POST['selectSearchDD_emails_edu'])?_f::getAntiXSS($_POST['selectSearchDD_emails_edu']):"";	// поиск по мыльному домену @..edu
	 $selectSearchDD_emails			= !empty($_POST['selectSearchDD_emails'])?_f::getAntiXSS($_POST['selectSearchDD_emails']):"";					// поиск по мыльному домену
	 $Search = !empty($_POST['Search'])?_f::getAntiXSS($_POST['Search']):"";

   $lat = (FLOAT)$_POST['lat'];
   $lon = (FLOAT)$_POST['lon'];

   $corStr=(int)$_POST['cor_str'];

   $limit_from = $corStr*$limit-$limit;

	 $search		= "";	// общий поиск по сайту
	 $location	= "1=1";	// локация и удаление
	 $TG="";
	 if ($category!="")
   {
		 $genderW	=  !empty($gender)? " gender='"._f::getAntiXSS($gender)."' ": " gender != 'null' ";
		 $type		=  " type='"._f::getAntiXSS($category)."' ";
		 $TG = "( {$type} AND {$genderW} )";
   }

	 if (!empty($selectSearchDD_emails_edu))
	 {
		 $email = " email LIKE ('%{$selectSearchDD_emails_edu}%') ";
		}
	 else
	 {
		 if(!empty($selectSearchDD_emails))
			{
				if ($selectSearchDD_emails=="other")
				{
					$email = " ( email NOT LIKE ('%.com%') AND email NOT LIKE ('%.edu%') )  ";
				}else	$email = " email LIKE ('%{$selectSearchDD_emails}%') ";
			}
	 }

	 if (!empty($Search))
	 {
		 $arrWHEREs = array
		(
			" name LIKE ('%{$Search}%')",
			" address LIKE ('%{$Search}%')",
			" description LIKE ('%{$Search}%')",
			" link LIKE ('%{$Search}%')",
			" vlink LIKE ('%{$Search}%')",
			" email LIKE ('%{$Search}%')",
			" type LIKE ('%{$Search}%')",
			" age LIKE ('%{$Search}%')",
			" gender LIKE ('%{$Search}%')",
			" price LIKE ('%{$Search}%')",
			" date LIKE ('%{$Search}%')",
		);
		 $search = " ( ".implode(" or ", $arrWHEREs)." ) ";
	} else $search ="";

		$arrWHERE = array();

	 if (!empty($TG))			$arrWHERE[]=$TG;
	 if (!empty($email))	$arrWHERE[]=$email;
	 $search2 = implode(" and ", $arrWHERE);
	 $AND = empty($search2) || empty($search) ?" ":" AND ";
	 $search = trim($search.$AND.$search2);
	 if (empty($search)) $search="1=1";

	 if (!empty($lat))
	 {
		 $location = "( ( ACOS( SIN( {$lat} * PI() / 180) * SIN(lat * PI() / 180) + COS( {$lat} * PI() / 180) * COS(lat * PI() / 180) * COS(({$lon} - lng) * PI() / 180) ) * 180 / PI()) * 60 * 1.1515)<=$d";
	 }
	 $qr = "SELECT * FROM markers WHERE   ( ( {$location} ) AND ( {$search} ) AND price BETWEEN {$minPrice} AND {$maxPrice}  ) AND varifMail='Ok' ORDER BY `date` DESC ";
 $data["qr"]= IS_DEBUG===TRUE?$qr:"is debug off";
 $_SESSION['query']=$qr;
	 $result = $bd->query($qr." LIMIT $limit_from, $limit ");
    $data["kolVo"]=0;
   // Creates an array of strings to hold the lines of the KML file.
 setKML();

	$kol_td = 1;
$resForData = $result;
if (!empty($isMobile))
{
	//echo "Search result file kml";
	$d = _t::contentAddsMobile($resForData);
}else
{
	//echo "Search result file kml";
	$d = _t::contentAddsDesctop($resForData);
}
	$data['content']=array();
	$data['content']=$d['content'][0];
	for ($j=0; $j<count($d['row']); $j++){
		$row = $d['row'][$j];
   $data["kolVo"]++;
   addKML($row["id"],$row["name"],$row["address"],$row["description"],$row["link"],$row["vlink"],$row["email"],$row["pic"],$row["type"],$row['gender'],$row["lng"],$row["lat"]);
   $data["markers"]["lng"][]=$row["lng"];
   $data["markers"]["lat"][]=$row["lat"];
	 }


Это наверное в этой части кода формируется поиск?
if (!empty($TG))			$arrWHERE[]=$TG;
	 if (!empty($email))	$arrWHERE[]=$email;
	 $search2 = implode(" and ", $arrWHERE);
	 $AND = empty($search2) || empty($search) ?" ":" AND ";
	 $search = trim($search.$AND.$search2);
	 if (empty($search)) $search="1=1";

Я просто пока еще не силен в программировании. Потому возможно мои вопросы довольно глупы.
По моему решил, and и AND на or и OR поменял. Огромное спасибо форуму. Эффект генерала в полной мере доказан еще раз.

dmitriymar 21.05.2013 16:17

Цитата:

Сообщение от andreydial
Я просто пока еще не силен в программировании. Потому возможно мои вопросы довольно глупы.

И вы, вот так вот сразу, хотите с 3 мя языками разобраться и базой ?
Вы себя переоцениваете явно , не тратьте своё время и обратитесь сразу в раздел http://javascript.ru/forum/job/ либо на биржи фриланса

andreydial 21.05.2013 17:16

Цитата:

Сообщение от dmitriymar (Сообщение 251940)
И вы, вот так вот сразу, хотите с 3 мя языками разобраться и базой ?
Вы себя переоцениваете явно , не тратьте своё время и обратитесь сразу в раздел http://javascript.ru/forum/job/ либо на биржи фриланса

Пока потихоньку получается. Книжки читать безусловно хорошее дело. Но без реальных применений теория тоже пшик. Да и на форуме есть добрые люди.:)

andreydial 23.05.2013 01:54

И все таки прошу помощи. Как переделать запрос
if (!empty($TG))            $arrWHERE[]=$TG;
	     if (!empty($email))    $arrWHERE[]=$email;
	     $search2 = implode(" and ", $arrWHERE);
	     $AND = empty($search2) || empty($search) ?" ":" AND ";
	     $search = trim($search.$AND.$search2);
	     if (empty($search)) $search="1=1";

Чтобы в поиске не словоcочетания иcкались, а отдельные cлова?
Что-то не помогло замена AND на OR

ed-210 23.05.2013 02:27

Я бы вам рекомендовал почитать и разобраться с регулярными выражениями и функциями поиска по шаблону в PHP,
такими как: preg_match() и preg_replace() и, возможно, с функцией preg_split()

andreydial 23.05.2013 02:36

Мне же надо в БД искать. Может можно просто запрос к БД соответствующий делать без вызова каждой записи и поиска совпадения. Я думаю можно, просто не знаю какой он должен быть.

edison 23.05.2013 03:44

Т.е вы хотите при вводе словосочетания искать не полное совпадение, а по отдельности каждое слово? Или у вас при вводе одного слова не ищет?
Ну во первых это форум по js ))
Во вторых. Нужный кусок кода вот:
$arrWHEREs = array
        (
            " name LIKE ('%{$Search}%')",
            " address LIKE ('%{$Search}%')",
            " description LIKE ('%{$Search}%')",
            " link LIKE ('%{$Search}%')",
            " vlink LIKE ('%{$Search}%')",
            " email LIKE ('%{$Search}%')",
            " type LIKE ('%{$Search}%')",
            " age LIKE ('%{$Search}%')",
            " gender LIKE ('%{$Search}%')",
            " price LIKE ('%{$Search}%')",
            " date LIKE ('%{$Search}%')",
        );

его и нужно править, если я правильно понял , что вы хотите.
Или разбивать $Search на слова и создавать еще кучу LIKE либо объединять поля через concat и создавать столько LIKE сколько слов в запросе, но тут уже нужно изучать структуру бд, может быть не выгодно так делать. Либо юзать полнотекстовой поиск MATCH() AGAINST(),FULLTEXT ну или как альтернатива Sphinx.
И третье, учится на том коде который вы привели не стоит.

andreydial 23.05.2013 11:19

Хочу по отдельности каждое слово. Но ведь в той части кода что привел я (те 6 строк внизу) формируется запрос и добавляется AND(OR) между словами.
А в том что вы привели, уже идет сам поиск. Или я не прав?

edison 23.05.2013 13:57

В том что я привел идет вставка из поля поиска, и туда вставляется все, что в строке поиска не разделяя никакими or, and и как я написал выше разделять нужно переменную $Search

допустим $Search='вася пупкин';
и
$Search or $Search
будет
вася пупкин or вася пупкин - хоть как ты меняй or на and всеравно будет целоиковое 'вася пупкин'
а не
вася or пупкин or вася or пупкин
и вставить в середину можно только разбивая переменную $Search и переписывая этот кусок кода.
Да и выше я написал что можно и не разделять, если использовать полнотекстовой поиск, но нужно будет все равно тот кусок менять, а еще и индексы бд. В общем в любом случае вам работать именно с тем куском кода который я привел.
А то, что вы привели - там совершенно в другом месте выставляется оператор, и к вашей задаче никак не относится.

andreydial 25.05.2013 01:03

Вроде нашел обработку каждого слова. Еще один маленький вопрос. Как организовать цикл для массива
if (!empty($Search))
	 {
		 $arrWHEREs = array
		(
			" name LIKE ('%{$Search}%')",
			" address LIKE ('%{$Search}%')",
			" description LIKE ('%{$Search}%')",
			" link LIKE ('%{$Search}%')",
			" vlink LIKE ('%{$Search}%')",
			" email LIKE ('%{$Search}%')",
			" type LIKE ('%{$Search}%')",
			" age LIKE ('%{$Search}%')",
			" gender LIKE ('%{$Search}%')",
			" price LIKE ('%{$Search}%')",
			" date LIKE ('%{$Search}%')",
		);
		 $search = " ( ".implode(" or ", $arrWHEREs)." ) ";
	} else $search ="";

В который встроить такую обработку
if($search) {
	    //получаем массов чистых слов
	    $words = clearWords($search);
	    //добавляем ограничители для формирования условия WHERE к каждому слову
	    foreach($words as $k=>&$v) $v="'".$v."%'";
	    //формируем условие WHERE
	    $where = implode(" OR header like ".clearWords($search);
	    //отрезаем первое " OR" из условия
	    $where = preg_replace("/^\sOR/","",$where);
	    //формируем окончательный запрос к БД
	    //$query = "SELECT * FROM table WHERE ".$where;
	}


Ну или как лучше всего совместить эти два условия?

andreydial 25.05.2013 02:12

Почему не работает поиск если сделать так
if (!empty($Search))
	 {
	 	$words = clearWords($Search);
	 	foreach($words as $k=>&$v) $v="'".$v."%'";
		 {$arrWHEREs = array
		(
			" name LIKE ('%{clearWords($search)}%')",
			" address LIKE ('%{clearWords($search)}%')",
			" description LIKE ('%{clearWords($search)}%')",
			" link LIKE ('%{clearWords($search)}%')",
			" vlink LIKE ('%{clearWords($search)}%')",
			" email LIKE ('%{clearWords($search)}%')",
			" type LIKE ('%{clearWords($search)}%')",
			" age LIKE ('%{clearWords($search)}%')",
			" gender LIKE ('%{clearWords($search)}%')",
			" price LIKE ('%{clearWords($search)}%')",
			" date LIKE ('%{clearWords($search)}%')",
		);}
		 $search = " ( ".implode(" or ", $arrWHEREs)." ) ";

	} else $search ="";

andreydial 25.05.2013 11:33

Может просто для description новую переменную организовать и все. В принципе поиск по словам только для этого поля необходим.

edison 25.05.2013 15:47

я бы делал через полнотекстовой поиск, т.к. можно отсортировать по релевантности
if(!empty($Search)){
	$arrWHEREs=array();
	$Searchs=preg_split('/\s+/',$Search,-1,PREG_SPLIT_NO_EMPTY);
	for($i=0,$s=sizeof($Searchs);$i<$s;$i++){
//		if(mb_strlen($Searchs[$i])<2)continue; // раскомментировать если не нужны слова менее 2х символов пример: 'маша и петя' - 'и' не войдет в выборку
		$arrWHEREs=array_merge($arrWHEREs,array
			(
				" name LIKE ('%{$Searchs[$i]}%')",
				" address LIKE ('%{$Searchs[$i]}%')",
				" description LIKE ('%{$Searchs[$i]}%')",
				" link LIKE ('%{$Searchs[$i]}%')",
				" vlink LIKE ('%{$Searchs[$i]}%')",
				" email LIKE ('%{$Searchs[$i]}%')",
				" type LIKE ('%{$Searchs[$i]}%')",
				" age LIKE ('%{$Searchs[$i]}%')",
				" gender LIKE ('%{$Searchs[$i]}%')",
				" price LIKE ('%{$Searchs[$i]}%')",
				" date LIKE ('%{$Searchs[$i]}%')",
			));
	}
	$search=" ( ".implode(" or ", $arrWHEREs)." ) ";
}else $search="";

что там у вас в защите от xss и обеспечивает ли та защита защиту от sqlinj я хз.

andreydial 25.05.2013 23:40

Цитата:

Сообщение от edison (Сообщение 252690)
я бы делал через полнотекстовой поиск, т.к. можно отсортировать по релевантности
if(!empty($Search)){
	$arrWHEREs=array();
	$Searchs=preg_split('/\s+/',$Search,-1,PREG_SPLIT_NO_EMPTY);
	for($i=0,$s=sizeof($Searchs);$i<$s;$i++){
//		if(mb_strlen($Searchs[$i])<2)continue; // раскомментировать если не нужны слова менее 2х символов пример: 'маша и петя' - 'и' не войдет в выборку
		$arrWHEREs=array_merge($arrWHEREs,array
			(
				" name LIKE ('%{$Searchs[$i]}%')",
				" address LIKE ('%{$Searchs[$i]}%')",
				" description LIKE ('%{$Searchs[$i]}%')",
				" link LIKE ('%{$Searchs[$i]}%')",
				" vlink LIKE ('%{$Searchs[$i]}%')",
				" email LIKE ('%{$Searchs[$i]}%')",
				" type LIKE ('%{$Searchs[$i]}%')",
				" age LIKE ('%{$Searchs[$i]}%')",
				" gender LIKE ('%{$Searchs[$i]}%')",
				" price LIKE ('%{$Searchs[$i]}%')",
				" date LIKE ('%{$Searchs[$i]}%')",
			));
	}
	$search=" ( ".implode(" or ", $arrWHEREs)." ) ";
}else $search="";

что там у вас в защите от xss и обеспечивает ли та защита защиту от sqlinj я хз.

Спасибо, сейчас попробую ваш вариант. Защиту меня не просили смотреть, посему это потом как нибудь. Просили только слова разделить.:)

Cупер, работает как надо! :dance: Вроде бы. Огромное спасибо.
Но если раскомментировать 5 строку, то поиск перестает работать.

edison 26.05.2013 01:21

mbstring небось не включена
mb_strlen на strlen
или включать mbstring


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