2011-08-29 179 views
7

我正在尝试为基于库存的网站创建搜索引擎。问题是我有bbtags内的信息(如[b]test[/b] sentence,test应该被估价为3,而sentence应该被估价为1)。PHP mysql搜索查询

这是一个索引的例子:
My test sentence, my my(有一个SKU的TST-DFS
数据库:

|Product| word |relevancy| 
| 1 | my | 3 | 
| 1 | test | 1 | 
| 1 |sentence| 1 | 
| 1 | TST-DFS| 10 | 

但我怎么会匹配TST-DFS如果用户键入TST DFS?我希望该SKU有一个相关性说8,而不是完整10 ..

我听说MySQL中的全文搜索功能将有所帮助,但我似乎无法找到一种好方法做到这一点。我想避免诸如UNION之类的事情,并尽可能优化查询。

任何帮助提出一个好的系统,这将是伟大的。

感谢, 最大

+0

你不能使用MySQL的'FULLTEXT'能力,或者是当你说“指数”是什么意思? – Bojangles

+0

问题是我有很多重要的信息,但是MySQL的FULLTEXT并不知道它很重要(如sku数字,产品名称和其他某些词)。因此,我将每个产品的每个单词编入索引,并且我不相信MySQL的FULLTEXT可以帮助我搜索每一行。 – Ben

+0

哦对。据我所见,不,“FULLTEXT”根本就没有用处。真是太遗憾了,因为它是MySQL的一部分。 – Bojangles

回答

5

但是,如果用户在TST DFS中键入,我将如何匹配TST-DFS?
我想那个SKU拥有的相关说8,而不是完整的10 ..

如果我得到了正确的问题,答案其实很容易。
那么,如果你锻造你的查询一点点,然后发送到MySQL。

好的,假设我们有$query,它包含TST-DFS。我们要关注字跨度? 我想我们应该,因为大多数搜索引擎做,所以:

$ok=preg_match_all('#\w+#',$query,$m); 

现在若该模式匹配 ... $m[0]包含单词在$query名单。
这可以针对您的SKU进行微调,但与AND时尚中的完整单词匹配几乎是用户所假定的。 (因为它发生在谷歌和雅虎)

然后,我们需要烹制一个$expr表达式,将被注入到我们的最终查询中。

if(!$ok) { // the search string is non-alphanumeric 
    $expr="false"; 
} else { // the search contains words that are no in $m[0] 
    $expr=''; 
    foreach($m[0] as $word) { 
    if($expr) 
     $expr.=" AND "; // put an AND inbetween "LIKE" subexpressions 
    $s_word=addslashes($word); // I put a s_ to remind me the variable 
           // is safe to include in a SQL statement, that's me 
    $expr.="word LIKE '%$s_word%'"; 
    } 
} 

现在$expr应该像"words LIKE '%TST%' AND words LIKE '%DFS%'"

与该值,我们可以构建最终的查询:

$s_expr="($expr)"; 
$s_query=addslashes($query); 

$s_fullquery= 
"SELECT (Product,word,if((word LIKE '$s_query'),relevancy,relevancy-2) as relevancy) ". 
"FROM some_index ". 
"WHERE word LIKE '$s_query' OR $s_expr"; 

其中应读为 “TST-DFS”:

SELECT (Product,word,if((word LIKE 'TST-DFS'),relevancy,relevancy-2) as relevancy) 
FROM some_index 
WHERE word LIKE 'TST-DFS' OR (word LIKE '%TST%' AND word LIKE '%DFS%') 

正如您所看到的,在第一个SELECT行中,如果匹配的部分,MySQL将返回相关-2

在第三个时,WHERE条款,如果完全匹配失败,$s_expr部分匹配查询,我们提前熟,被试代替。

+0

已更正。我的逻辑错了。 **现在**'$ expr'应该看起来像'words LIKE'%TST%'和单词LIKE'%DFS%'' – ZJR

+0

那么你在哪里获得'相关性'列? – Ben

+0

从来没有想到上述情况,这将如何与多字查询工作?它似乎将自身与完美的单词进行比较,或者包含所有的子词,我对此是否正确? – Ben

0

我想补充一点被剥离所有特殊字符的,拼写错误,然后upcased一列(或创建已被剥夺和upcased上的文字进行比较的功能)。这样你的相关性就会一致。

2

我喜欢小写的一切,去掉特殊字符(如在一个电话号码或信用卡我把所有的东西两侧,是不是一个数字)

1

,而不是试图创建自己的FTS解决方案,您可以尝试使MySQL FTS引擎符合您的要求。我所看到的是创建一个新表来存储您的FTS数据。为您想要具有不同相关性的每个不同数据创建一列。对于你的sku领域,你可以存储原始sku,空格,下划线,连字符和其他任何特殊字符。然后保存一个精简版,删除所有这些东西。你也可能想要存储一个删除了前导零的版本,因为人们经常会这样做。您可以将所有这些变体存储在同一列中。将产品名称存储在另一列中,并将产品说明存储在另一列中。在每列上创建一个单独的索引。然后,当您进行搜索时,您可以单独搜索每个列,并根据您认为该列的重要程度来倍增结果的排名。因此,您可以将sku结果乘以10,标题乘以5,并将描述结果保留原样。您可能需要做一些实验才能获得想要的结果,但最终可能比创建自己的索引更简单。

+0

我有描述中围绕字幕的bbcode。我可以在bbcodes之间采取一切行动,并将所有世界合并(在它们之间有空格)在一列中,并将该列乘以3?另外,你可以举一个简单的例子来说明使用不同乘数的全文吗? – Ben

+0

如果您愿意扩展您的答案,我很乐意为此问题添加赏金。 – Ben

1

创建关键字表。沿线的东西:

integer keywordId (autoincrement) | varchar keyword | int pointValue 

将所有可能的关键字,skus等分配到此表中。创建一个表,后桥的关键词,(假设postId是您在原始表已经分配的ID)的线沿线的:

integer keywordId | integer postId 

一旦你有了这个,你可以很容易的关键字添加到每个岗位因为它感兴趣。为给定后计算总点值,查询如下面应该做的伎俩:

SELECT sum(pointValue) FROM keywordPostsBridge kpb 
JOIN keywords k ON k.keywordId = kpb.keywordId 
WHERE kpb.postId = YOUR_INTENDED_POST 
1

我认为解决的办法非常简单,除非我错过了什么。

基本上运行两次搜索,一次是完全匹配,另一次是匹配或正则匹配。

将两个结果集合在一起,如匹配左连接完全匹配。然后例如:

final_relevancy = (IFNULL(like_relevancy, 0) + IFNULL(exact_relevancy, 0) * 3)/4 

虽然我没有尝试过。只是一个想法。

0
/* 
q and q1 - you table 
this query takes too much resources, 
make from it update-query (scheduled task or call it on_save if you develop new system) 
*/ 
SELECT 
     CASE 
       WHEN word NOT REGEXP "^[a-zA-Z]+$" 
        /*many replace with junk characters 
        or create custom function 
        or if you have full db access install his https://launchpad.net/mysql-udf-regexp 
        */ 
       THEN REPLACE(REPLACE(word, '-', ' '), '#', ' ') 
       ELSE word 
     END word , 
     CASE 
       WHEN word NOT REGEXP "^[a-zA-Z]+$" 
       THEN 8 
       ELSE relevancy 
     END   relevancy 
FROM (SELECT 'my' word, 
       3  relevancy 

     UNION 

     SELECT 'test' word, 
       1  relevancy 

     UNION 

     SELECT 'sentence' word, 
       1   relevancy 

     UNION 

     SELECT 'TST-DFS' word, 
       10 relevancy 
     ) 
     q 

UNION 

SELECT * 
FROM (SELECT 'my' word, 
       3  relevancy 

     UNION 

     SELECT 'test' word, 
       1  relevancy 

     UNION 

     SELECT 'sentence' word, 
       1   relevancy 

     UNION 

     SELECT 'TST-DFS' word, 
       10 relevancy 
     ) 
     q1 
0
it is a page coading where query result shows 

**i can not use functions by use them work are more easier** 

<html> 
<head> 
</head> 
<body> 
<?php 
//author S_A_KHAN 
//date 10/02/2013 
$dbcoonect=mysql_connect("127.0.0.1","root"); 
if (!$dbcoonect) 
{ 
die ('unable to connect'.mysqli_error()); 
} 
else 
{ 
echo "connection successfully <br>"; 

} 
$data_base=mysql_select_db("connect",$dbcoonect); 


if ($data_base==FALSE){ 

die ('unable to connect'.mysqli_error($dbcoonect)); 
    } 
else 
    { 
echo "connection successfully done<br>"; 
    ***$SQLString = "select * from user where id= " . $_GET["search"] . ""; 
$QueryResult=mysql_query($SQLString,$dbcoonect);*** 

echo "<table width='100%' border='1'>\n"; 
    echo "<tr><th bgcolor=gray>Id</th><th bgcolor=gray>Name</th></tr>\n"; 
    while (($Row = mysql_fetch_row($QueryResult)) !== FALSE) { 
     echo "<tr><td bgcolor=tan>{$Row[0]}</td>"; 
     echo "<td bgcolor=tan>{$Row[1]}</td></tr>"; 
    } 
} 
?> 

</body> 
</html>