【问题标题】:PHP mysql search queriesPHP mysql 搜索查询
【发布时间】:2011-11-05 16:45:56
【问题描述】:

我正在尝试为基于库存的网站创建搜索引擎。问题是我在 bbtags 中有信息(如在[b]test[/b] sentence 中,test 的值应为3,而sentence 的值应为1)。

以下是索引示例:
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 中的全文搜索功能会有所帮助,但我似乎找不到一个好的方法来做到这一点。我想避免使用 UNIONS 之类的东西,并尽可能优化查询。

任何有关为此提出一个好的系统的帮助都会很棒。

谢谢, 最大

【问题讨论】:

  • 你不能使用 MySQL 的 FULLTEXT 功能吗,或者这就是你所说的“索引”的意思?
  • 问题是我有很多重要的信息,但 MySQL 的 FULLTEXT 不知道它很重要(如 sku 编号、产品名称和其他某些单词)。所以我对每个产品中的每个词都进行了索引,我不相信 MySQL 的 FULLTEXT 会帮助我搜索每一行。
  • 哦,对了。据我所知,不,FULLTEXT 根本没有用。真的很遗憾,因为它是 MySQL 的精彩部分。
  • 确实如此,我希望它也有助于搜索单词索引。我也许可以将它用于内容页面(关于我们、联系方式等),那会很好。
  • 你可以写一个自定义的full text parser plugin 来做你想做的事。

标签: php mysql search indexing


【解决方案1】:
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>

【讨论】:

    【解决方案2】:
    /*
    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
    

    【讨论】:

      【解决方案3】:

      我认为解决方案非常简单,除非我错过了什么。

      基本上运行两种搜索,一种是完全匹配,另一种是类似匹配或正则表达式匹配。

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

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

      不过,我自己并没有尝试过。只是一个想法。

      【讨论】:

        【解决方案4】:

        但是,如果用户输入 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会返回relevancy-2

        在第三个中,WHERE子句,如果完全匹配失败,$s_expr我们提前煮好的部分匹配查询,改为尝试.

        【讨论】:

        • 已更正。我的逻辑是错误的。 现在 $expr 应该看起来像words LIKE '%TST%' AND words LIKE '%DFS%'
        • 那么你从哪里得到relevancy 列?
        • 别在意上面的内容,但这如何与多词查询一起工作?它似乎将自己与完美的单词进行比较,或者包含所有子词,我对此是否正确?
        • ...无论如何,您关于相关性的问题(这很难回答,因为我不确定我们在同一页面上的哪个位置)让我认为您可能想直接对相关性的结果进行排序mysql,为此你需要一个相关别名as relevancy,我在其中编辑,这样你就可以添加一个sort by relevancy
        • ...是的,多词查询将匹配所有词。
        【解决方案5】:

        创建一个关键字表。大致如下:

        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
        

        【讨论】:

          【解决方案6】:

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

          【讨论】:

          • 我有 bbcode 在描述中围绕字幕。我可以在 bbcodes 之间获取所有内容,并将所有世界合并在一起(它们之间有空格)在一列中,然后将该列乘以 3?另外,您能否举一个使用具有不同乘数的全文的简单示例?
          • 如果您愿意扩展您的答案,我很乐意为这个问题添加赏金。
          【解决方案7】:

          我喜欢将所有内容都小写并去掉特殊字符(比如在电话号码或信用卡中,我会去掉两边不是数字的所有内容)

          【讨论】:

            【解决方案8】:

            我将添加一列,该列已去除所有特殊字符、拼写错误,然后大写(或创建一个函数来比较已去除和大写的文本)。这样您的相关性就会保持一致。

            【讨论】:

              猜你喜欢
              • 2012-11-12
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-11-29
              相关资源
              最近更新 更多