Php 实时搜索引擎查询背后的逻辑

Php 实时搜索引擎查询背后的逻辑,php,html,mysql,arrays,logic,Php,Html,Mysql,Arrays,Logic,我在使用AJAX和PHP创建多字段实时搜索引擎时遇到问题 到目前为止,不需要搜索多个字段,所以我有一个简单的查询,只对一个字段有效 由于使用onkeyup功能进行实时搜索,我发现了一些问题。我需要解释的第一个问题是: 表的结构非常简单:zipcode | city 例如,有人输入12345;当然,这将是zipcode。但是如果有人输入了12345家乡,那么第一个关键字将是zipcode,第二个是城市,该怎么办 关键字将通过使用preg_split('/[\s]+/',$search_term)进

我在使用AJAX和PHP创建多字段实时搜索引擎时遇到问题

到目前为止,不需要搜索多个字段,所以我有一个简单的查询,只对一个字段有效

由于使用
onkeyup
功能进行实时搜索,我发现了一些问题。我需要解释的第一个问题是:

表的结构非常简单:
zipcode | city

例如,有人输入
12345
;当然,这将是zipcode。但是如果有人输入了12345家乡,那么第一个关键字将是zipcode,第二个是城市,该怎么办

关键字将通过使用
preg_split('/[\s]+/',$search_term)
进行拆分,因此我收到一个包含要搜索的单个关键字的数组。在上述情况下,它将是:
键[0]=>12345
键[1]=>家乡

我使用的查询如下所示:

$where = "";

$search_term = preg_split('/[\s]+/', $search_term); //splits the whole string into single keywords
$total_search_terms = count($search_term); //counts the array-keys from $search_term

foreach ($search_term as $key=>$single_term) {

        $where .= "`zipcode` LIKE '$single_term%' OR `city` LIKE '$single_term%' ";

        if ($key != ($total_search_terms - 1)){ //adds AND to the query in case in case of a non empty array-key 
            $where .= " AND ";
        }

}

$query = $db->query("SELECT COUNT(*) FROM table WHERE $where");
...
好的,到目前为止还不错。现在的问题是,关键字可以一次又一次地匹配每个字段

再举一个例子:

如果从上面输入
12345家乡
,则表示
键[0]=>12345
可以匹配字段
zipcode
城市
。此条件类似于
键[1]=>家乡
,甚至可以匹配字段
zipcode
城市
。因此,即使以另一种方式输入:
家乡12345
的意思也是一样的

这是我遇到的第一个问题

我正在寻找一种逻辑来构造查询。因此,在输入
12345家乡时
我想要这样的东西:

key[0]=>12345
匹配字段
zipcode
时,不要检查
key[1]=>homerium
中是否匹配
zipcode
city
中,因为
key[0]
已经匹配
zipcode
中的字段,所以
key[1]
需要是
city

更新

好的,告诉我的第二个问题,我想让你看看
david strachan
他提到,当城市包含多个字符串时,就会出现问题。假设搜索字符串类似于:

12345 New York
关键是:

key[0] => 12345, key[1] => New, key[2] => York
好的,现在的问题是,我可以检查其中一个键是否包含整数,如果字符串长度正好为5,我知道它将是zipcode

key[0] => 12345 //if ( stringlen(key[0|) === 5) === true  && is_int(key[0]) === true) {zipcode}
到目前为止还不错,但真正的问题是城市背后的逻辑。我的第一个想法是,我可以说所有不包含整数的键都必须是城市,这样我就可以将它们转换成一个键

key[1] => New, key[2] => York //if ( !is_int(key[1|) === true && !is_int(key[2|) === true)  {$create_one_key = array_fill_keys(key[1], key[1]+key[2]);}

好的,但是万一我将来想添加街道名称呢?我不知道如何区分和测试街道名称,甚至城市名称

通过添加0来检查
$search\u term[0]
是字符串(city)还是int(zipcode),然后相应地格式化查询

$search_term = '1234 paisley';
$search_term = preg_split('/[\s]+/', $search_term); //splits the whole string into single keywords
$total_search_terms = count($search_term); //counts the array-keys from $search_term
$test = $search_term[0]+0;//If string returns 0
if($total_search_terms == 1){
    if ($test == 0 ){
        $where = "WHERE `city` LIKE `%$search_term[0]%`";
         }else{
        $where = "WHERE `zipcode` LIKE `%$search_term[0]%` ";
        }   
    }else{
    if ($test == 0 ){
        $where = "WHERE `zipcode` LIKE `%$search_term[1]%` AND `city` LIKE `%$search_term[0]%`";
        }else{
        $where = "WHERE `zipcode` LIKE `%$search_term[0]%` AND `city` LIKE `%$search_term[1]%`";
        }   
}   
 $query = "SELECT COUNT(*) FROM table $where";
echo $query;
一个问题是你如何对待纽约。我将告诉你如何解决这个问题

编辑


纽约
$total\u search\u terms>2

另一种方法是搜索MySQL数据库。下面的代码使用PDO

<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.2/jquery-ui.js"></script>
<link rel="stylesheet" href="/resources/demos/style.css" />
<script type="text/javascript">
jQuery(document).ready(function(){
    $('#zipsearch').autocomplete({source:'suggest.php', minLength:2});
});
</script>
<style type="text/css">
    li.ui-menu-item { font-size:10px}
</style>
</head>
<body>
<h2>jQuery UI Autocomplete - With MySQL  </h2>
<form onsubmit="return false;">
    Search:
    <input id="zipsearch" type="text" size ="60"/>
</form>

当键[0]=>12345与字段zipcode匹配时,不要检查键[1]=>在zipcode或city中是否匹配,因为键[0]与zipcode中已经匹配,所以键[1]需要是city是很合理的。
为什么要这样做?我想是为了优化?你好。仔细看你们的问题,我注意到它们都是用小写字母写的。你的英语似乎很好,我能麻烦你用首字母大写吗?有时人们会花时间来修正你的问题,使它们更具可读性,这样你就可以节省一些时间了@半身人。好的,谢谢你的提示。我将来会记住这一点。谢谢。@Ejay我想那样做是因为我遇到了第二个问题。我将更新我的问题,以提供有关这方面的进一步信息。谢谢你把城市和街道的名字复杂化了。让用户输入逗号分隔的地址将解决很多问题,例如zipcode、城市、街道名称。或者更好,如果你能使用多输入boxeshello,非常感谢你的回答。你说的问题正是我的第二个问题。如果我想将街道名称添加到表中,或者城市有多个字符串,该怎么办?只要唯一的整数值是zipcode,并且城市名称中有一个或多个字符串,就可以使用这种方法(提示
$total\u search\u terms>2
)。如果你想搜索街道地址,你应该问一个新问题你好,很抱歉我迟到了。我现在还很紧张,不能马上回答。我更新了我的问题。感谢
$search\u term
纽约12345
纽约12345
因此,如果$total\u search\u terms>2,则
$search\u term[0]
$search\u term[2]
将是zipcode<代码>字符串(键[0])==5可能是巴黎?字符串(键[0])==5可能是巴黎?是安静的权利,但这只是两个条件之一。所以所有zipcode的长度正好是5个字符,所以这是zipcode的第一个提示。下一个将是is_int()==true/false将确认这一点。好的,回到您的提示$total_search_terms>2:[0]或[2]将是zipcode,这是如何工作的?没有检查的条件,如是否完整等。?我对此有点困惑。谢谢
require("dbinfo.php");//db connection strings
// if the 'term' variable is not sent with the request, exit
if ( !isset($_REQUEST['term']) )
    exit;
$term = $_REQUEST['term'];
 if (is_numeric($term)){
    $query = "SELECT * from ziptest WHERE zip LIKE ? OR address LIKE ? LIMIT 0,10";
  }else{
    $query = "SELECT * from ziptest WHERE city LIKE ? OR state LIKE ? LIMIT 0,10";  
  }
$term.="%";  

// connect to the database  
try {  
    $dbh = new PDO("mysql:host=$host;dbname=$database", $username, $password);  
    $dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );  
  // Prepare statement
    $stmt = $dbh->prepare($query);
    // Assign parameters
    $stmt->bindParam(1,$term);
    $stmt->bindParam(2,$term);
    // setting the fetch mode  
    $stmt->setFetchMode(PDO::FETCH_ASSOC); 
    $stmt->execute();  
    $data = array();
        while($row = $stmt->fetch()) {  
            $data[] = array(
                'label' => $row['address'] .', '. $row['city'] .', '. $row['state'] .', '.$row['zip'] ,
                'value' => "ID ".$row['id'] .': '.$row['address'] .', '. $row['city'] .', '. $row['state'] .', '.$row['zip']
            );
        }
    echo json_encode($data);
}  
catch(PDOException $e) {  
    echo "I'm sorry I'm afraid you can't do that.". $e->getMessage() ;// Remove or modify after testing 
    file_put_contents('PDOErrors.txt',date('[Y-m-d H:i:s]'). $e->getMessage()."\r\n", FILE_APPEND);  
}  
// close the connection
$dbh = null;