搜索查询不够准确

时间:2018-01-14 12:55:30

标签: php search sqlite

我尽我所知在PHP完成了搜索查询,但需要进行一些改进:

  1. 当我搜索说'什么是食物'并且我在数据库中有'什么是食物'时,所有结果都包含关键词'what','is','food'。期望的行为是显示包含确切短语“what is food”(第一个)

  2. 的结果
  3. 只突出显示查询中的最后一个单词,我想突出显示所有单词

  4. 期望的行为:正确的答案显示在顶部,无论其在数据库中的位置如何。

    我目前的代码是这样的:

    if (isset($_GET["mainSearch"]))
    {
      $condition = '';
      $mainSearch = SQLite3::escapeString($_GET['mainSearch']);
      $keyword = $_GET['mainSearch'];
      $query = explode(" ", $keyword);
      $perpageview=7;
    
      if ($_GET["pageno"])
      {
          $page=$_GET["pageno"];
      }
      else
      {
          $page=1;
      }
    
      $frompage = $page*$perpageview-$perpageview;
    
      foreach ($query as $text)
      {
          $condition .= "question LIKE '%".SQLite3::escapeString($text)."%' OR answer LIKE '%".SQLite3::escapeString($text)."%' OR ";
      }
      foreach ($query as $text_2)
      {
          $condition_2 .= "bname LIKE '%".SQLite3::escapeString($text_2)."%' OR bankreq LIKE '%".SQLite3::escapeString($text_2)."%' OR ";
      }
    
      $condition = substr($condition, 0, -4);
      $condition_2 = substr($condition_2, 0, -4);
    
    
      $order = " ORDER BY quiz_id DESC ";
      $order_2 = " ORDER BY id DESC ";
      $sql_query = "SELECT * FROM questions WHERE " . $condition . ' '. $order.' LIMIT '.$frompage.','.$perpageview;
      $sql_query_count = "SELECT COUNT(*) as count FROM questions WHERE " . $condition .' '. $order;
      //$mainAnswer = "SELECT * FROM questions WHERE question LIKE '%$mainSearch%' or answer LIKE '%$mainSearch%'";
      $bank_query = "SELECT * FROM banks WHERE " . $condition_2 . ' LIMIT 1';
      $result = $db->query($sql_query);
      $resultCount = $db->querySingle($sql_query_count);
      $bankret = $db->query($bank_query);
      //$mainAnsRet = $db->query($mainAnswer);
      $pagecount = ceil($resultCount/$perpageview);
    
      if ($resultCount > 0)
      {
      if ($result && $bankret)
      {
          while ($row = $result->fetchArray(SQLITE3_ASSOC))
          {
    
              $wording = str_replace($text, "<span style='font-weight: bold; color: #1a0dab;'>".$text."</span>", $row['answer']);
    
               echo '<div class="quesbox_3">
                <div class="questitle">
                    <h2>'.$row["question"].'</h2>
                </div>
                <div class="quesanswer">'.$wording.'</div>
            </div>';
          }
          while ($brow = $bankret->fetchArray(SQLITE3_ASSOC))
          {
                $bname = $brow['bname'];
                $bankbrief = $brow['bankbrief'];
                $bankreq = $brow['bankreq'];
                $bankaddress = $brow['bankaddress'];
                $banklogo = $brow['banklogo'];
                $founded = $brow['founded'];
                $owner = $brow['owner'];
                $available = $brow['available'];
    
    
               echo '<div class="modulecontent">
                <div class="modulename">
                    <div class="mname">'.$bname.'</div>
                    <div class="mlogo"><img src="'.$banklogo.'"></div>
                </div>';
    
                if (strlen($bankreq) > 300)
                {
                    $bankcut = substr($bankreq, 0, 300);
    
                    $bankreq = substr($bankcut, 0, strrpos($bankcut, ' ')).'... <a href="bankprofile.php?bname='.$bname.'">Read More</a>';
                    echo '<div class="modulebrief">'.$bankreq.'</div>';
                }
                echo '<div class="modulelinks">
                    <div class="mfound">Founded: <span>'.$founded.'</span></div>
                    <div class="mowned">Ownd By: <span>'.$owner.'</span></div>
                </div>
            </div>';
    
                   // <div class="mavailable">Available for Export Loan: <span>'.$available.'</span></div>
          }
          ?>
          <div class="page_num">
          <?php
          for ($i=1; $i <= $pagecount; $i++) {
             echo '<a href="searchresult.php?mainSearch='.$mainSearch.'&pageno='.$i.'">'.$i.'</a>';
          }
          ?>
          </div>
          <?php
      }
      }
      else
      {
          $session_n = $_SESSION['log_id'];
          $sesdate = date('d/M/Y');
          echo "<div class='searchNone'><p>No results found</p></div>
          <div class='sendSearchQ'>
          <p>Please send us your question.</p>
          <form action='sendquestion.php' method='post' encytype='multipart/form-data'>
          <div class='searchQinputs'>
              <input type='text' name='searchQuestion' id='searchQuestion'placeholder='Whats your question'><br>
              <input type='submit' name='sendQuestion' id='sendQuestion' value='Send'>
              <input type='text' name='user' id='user' value='$session_n' style='display: none'>
              <input type='text' name='qDate' id='qDate' value='$sesdate' style='display: none'>
              <input type='text' name='status' id='status' value='0' style='display: none'>
              </div>
          </form>
          </div>";
      }
    }
    

5 个答案:

答案 0 :(得分:10)

在查询中添加可排序字段

首先我们需要简化您的问题

您可以将问题视为简单的关键字匹配,其中最重要的结果必须与输入的所有关键字匹配。

搜索:some search text应该返回包含任何单词['some', 'search', 'text']的所有结果,其中的结果与完全一致 "some search text"。< / p>

这意味着您需要创建一个聚合字段,允许根据匹配对结果进行排序。我知道这样做的唯一方法是在没有重构数据和/或代码的情况下使用MySql Case语句。

您的查询已简化

SELECT *
FROM questions
WHERE
    question LIKE '%[word1]%' OR answer LIKE '%[word1]%'
    OR question LIKE '%[word2]%' OR answer LIKE '%[word2]%'
    OR question LIKE '%[word3]%' OR answer LIKE '%[word3]%'
ORDER BY quiz_id DESC

案例[完全匹配]和排序

我们需要构建的是一个看起来有点像这样的查询:

SELECT *,
    (CASE WHEN
            question LIKE '%[full-search-query]%'
            OR answer LIKE '%[full-search-query]%'
        THEN 1 ELSE 0
    END) as fullmatch
FROM questions
WHERE
    question LIKE '%[word1]%' OR answer LIKE '%[word1]%'
    OR question LIKE '%[word2]%' OR answer LIKE '%[word2]%'
    OR question LIKE '%[word3]%' OR answer LIKE '%[word3]%'
ORDER BY fullmatch DESC, quiz_id DESC

调整代码

// your initial storage of the full search, before you split it on spaces
$keyword = $_GET['mainSearch'];

. . .

// build our sorting field
$sortFullMatch = "(CASE WHEN question LIKE '%".SQLite3::escapeString($keyword)."%' OR answer LIKE '%".SQLite3::escapeString($keyword)."%' THEN 1 ELSE 0 END) as fullmatch";

. . .

// adjust the query and sort
$order = " ORDER BY fullmatch DESC, quiz_id DESC ";
$sql_query = "SELECT *,". $sortFullMatch ." FROM questions WHERE ".$condition.' '.$order.' LIMIT '.$frompage.','.$perpageview;

这是做什么的?

我们在SELECT语句fulltext中添加了一个新字段。当问题或答案完全包含完整搜索时,此字段将为1,否则为0.然后只需对此字段进行排序。

高亮

至于您的突出显示问题,您只能替换$textmainSearch中每个字的循环中设置的$wording = str_replace($text, "<span style='font-weight: bold; color: #1a0dab;'>".$text."</span>", $row['answer']); 。因此,它只是集合中的最后一个单词。相反,你需要在这里做一个类似的循环。

您的代码

foreach($query as $text) {
    $wording = str_replace($text, "<span style='font-weight: bold; color: #1a0dab;'>".$text."</span>", $row['answer']);
}

调整

public class SomeClient {
    public static void main(String args[]) {
        TransactionXmlWriter txw      = new TransactionXmlWriter();
        TransactionType      tranType = getNextTransaction();

        try {
            txw.openXmlOutput("someFileName.xml");
            while(tranType != null) {
                txw.processObject(tranType);
                tranType = getNextTransaction();
            }
            txw.closeXmlOutput();
        } catch(JAXBException e) {
        } catch(FileNotFoundException e) {
        } catch(XMLStreamExceptoin e) {
        }
    }
}

答案 1 :(得分:3)

您可以使用Google的NLP apis来检测只是连词和单词的单词并且具有显着性的单词,这样您发送到数据库的查询就会忽略像&#34; what&#这样的单词34;或&#34;是&#34;这样您就可以为用户提供更好的体验。还有其他工具,如NLTK等,它们也可以用来使查询变得更聪明。

答案 2 :(得分:2)

出于性能原因,您应该使用REGEXP而不是多个LIKE说明。订购可以使用简单的ORDER BY指令完成,如下所示:

$keyword=$_GET['mainSearch'];
$pattern=join("|", array_filter(explode(" ", $keyword)));

$sql_query="SELECT * FROM questions
     WHERE (question REGEXP '$pattern') OR (answer REGEXP '$pattern')
     ORDER BY CONCAT(question, answer) LIKE '%$keyword%' DESC;";

使用preg_replace

可以轻松完成突出显示
 preg_replace("/($pattern)/",
       "<span style='font-weight: bold; color: #1a0dab;'>$1</span>",
       $row['answer']);

答案 3 :(得分:1)

首先在数据库中运行以下查询。

ALTER TABLE  questions  ADD FULLTEXT(question, answer);

然后使用以下查询进行搜索

if (isset($_GET["mainSearch"]))
{
  $condition = '';
  $mainSearch = SQLite3::escapeString($_GET['mainSearch']);
  $keyword = $_GET['mainSearch'];
  $query = explode(" ", $keyword);


  $puresearch=implode("*+*", $query);

  $myquery = "SELECT *,MATCH(question,answer) AGAINST('*".$keyword."*' IN BOOLEAN MODE) as relavance FROM questions WHERE MATCH(question,answer) AGAINST('*".$keyword."*' IN BOOLEAN MODE) ORDER BY ralavance DESC";

  $result = $db->query($myquery);

}

这是全文搜索,根据相关性为您提供结果,可以按降序排列,以便在第一点显示搜索更可靠的搜索结果。

答案 4 :(得分:0)

鉴于此test

create table test (
  tid integer PRIMARY KEY,
  ttext text NOT NULL
  );
  INSERT INTO test (
  tid,
  ttext
  ) VALUES (1,'what are you doing?'),(2,'this is your house?'),(3,'food chain'),(4,'what is food');

您的结束查询应如下所示

select *,
(case
when ttext like '%food%' then 1
else 0
end+
case
when ttext like '%chain%' then 1
else 0
end) as tsum
from test where ttext like '%food%' or ttext like '%chain%' 
order by tsum desc;

id  text           sum
 3  food chain      2
 4  what is food    1    

select *,
(case
when ttext like '%what%' then 1
else 0
end+
case
when ttext like '%is%' then 1
else 0
end+
case
when ttext like '%food%' then 1
else 0
end) as tsum
from test where ttext like '%what%' or ttext like '%is%' or ttext like '%food%' 
order by tsum desc;

id  text                sum
 4  what is food         3
 1  what are you doing?  1
 2  this is your house?  1
 3  food chain           1

select *,
(case
when ttext like '%this%' then 1
else 0
end+
case
when ttext like '%is%' then 1
else 0
end) as tsum
from test where ttext like '%this%' or ttext like '%is%' 
order by tsum desc;

id  text                sum
 2  this is your house?  2
 4  what is food         1

select *,
(case
when ttext like '%what%' then 1
else 0
end+
case
when ttext like '%is%' then 1
else 0
end+
case
when ttext like '%house%' then 1
else 0
end) as tsum
from test where ttext like '%what%' or ttext like '%is%' or ttext like '%house%' 
order by tsum desc;

id  text                sum
 2  this is your house?  2
 4  what is food         2
 1  what are you doing?  1

您可以在DB Fiddle

上测试上述所有查询

要构建此类查询并假设您使用的是PDO,那么您的PHP代码应该如下所示。

...
// Sample code for 1st example query
$keywrd1 = '%food%';
$keywrd2 = '%chain%';
// Prepare the command
$sth = $dbh->prepare('select *,
(case
when ttext like :keyword1 then 1
else 0
end+
case
when ttext like :keyword2 then 1
else 0
end) as tsum
from test where ttext like :keyword1 or ttext like :keyword2 
order by tsum desc');
// Bind the parameters
$sth->bindParam(':keyword1', $keywrd1, PDO::PARAM_STR);
$sth->bindParam(':keyword2', $keywrd2, PDO::PARAM_STR);
$sth->execute();
...