【问题标题】:Live search engine logic behind query查询背后的实时搜索引擎逻辑
【发布时间】:2013-04-14 09:45:27
【问题描述】:

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

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

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

表格的结构很简单:zipcode | city

比如有人输入12345;当然,这将是邮政编码。但是如果有人输入12345 hometown,那么第一个关键字是邮政编码,第二个是城市怎么办?

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

我使用的查询是这样的:

$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 hometown,则意味着key[0] => 12345可以匹配字段zipcodecity。此条件与key[1] => hometown 相同,即使这也可以匹配字段zipcodecity。所以,即使输入其他方式:hometown 12345 也一样。

这是我遇到的第一个问题。

我正在寻找一种逻辑来构建查询。所以如果输入12345 hometown,我想要这样的东西:

key[0] => 12345 匹配字段zipcode 时,不要检查key[1] => hometown 是否匹配zipcodecity,因为key[0] 已经匹配zipcode,所以key[1] 需要匹配是很合乎逻辑的是city

更新

好的,说我的第二个问题,我想让你看看david strachan的答案 他提到当城市包含多个字符串时会引起问题。假设搜索字符串类似于:

12345 New York

关键是:

key[0] => 12345, key[1] => New, key[2] => York

好的,现在的问题是我可以检查其中一个键是否包含整数,如果字符串长度正好为 5,我知道它将是邮政编码。

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]);}

好的,但是如果我以后想添加街道名称怎么办?我不知道如何区分和测试街道名称,甚至城市名称。

【问题讨论】:

  • when key[0] => 12345 matches field zipcode dont check key[1] => hometown if that matches in zipcode OR city because key[0] matches already in zipcode so it's quiet logical that key[1] needs to be city. 你为什么要这么做?我猜是出于优化目的?
  • 您好。浏览您的问题,我注意到它们都是用小写字母写的。你的英文好像不错,能麻烦你用首字母大写吗?有时人们会花时间解决您的问题以使其更具可读性,这样您就可以节省一些时间!
  • @halfer。好的,谢谢这个提示。我会记住这一点,以备将来之用。谢谢。
  • @Ejay 我想要这样,因为我遇到了第二个问题。我将更新我的问题以提供有关此的更多信息。谢谢
  • 我猜你已经把城市名称和街道名称复杂化了。让用户输入逗号分隔的地址将解决很多您的问题,例如,邮政编码、城市、街道名称。或者如果你可以使用多个输入框更好

标签: php html mysql arrays logic


【解决方案1】:

另一种方法是使用JQuery Autocomplete 搜索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>

suggest.php

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;

DEMO

【讨论】:

    【解决方案2】:

    通过添加 0 检查$search_term[0] 是 string(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_search_terms &gt; 2

    【讨论】:

    • 您好,非常感谢您的回答。你所说的问题正是我的第二个问题。如果我想在表格中添加街道名称或城市有多个字符串怎么办?
    • 只要整数值是邮政编码并且城市名称中有一个或多个字符串(提示$total_search_terms &gt; 2),就可以使用这种方法。如果您想搜索街道地址,您应该提出一个新问题
    • 您好,很抱歉我迟到了。我*现在还在忙,无法立即回答。我更新了我的问题。谢谢
    • $search_term 将是 12345 New YorkNew York 12345 所以如果 $total_search_terms > 2 $search_term[0]$search_term[2] 将是邮政编码。 stringlen(key[0]) === 5 可能是巴黎?
    • stringlen(key[0]) === 5 可能是巴黎?是安静的权利,但它只是两个条件之一。所以所有邮政编码的长度都是 5 个字符,因此这是邮政编码的第一个提示。下一个是 is_int()===true/false 将确认这一点。好的,回到你的提示 $total_search_terms > 2 : [0] 或 [2] 将是邮政编码是如何工作的?没有条件可以检查 is_int 等?我对此有点困惑。谢谢。
    猜你喜欢
    • 2015-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-20
    • 1970-01-01
    • 1970-01-01
    • 2017-05-15
    • 2011-11-02
    相关资源
    最近更新 更多