Domanda Query di ricerca non abbastanza accurata


Ho una query di ricerca eseguita da me al meglio delle mie conoscenze in PHP ma ci sono alcuni miglioramenti richiesti:

  1. Quando cerco "cosa è cibo" e ho "ciò che è cibo" nel database, vengono visualizzati tutti i risultati contenenti una delle parole chiave "cosa", "è", "cibo". Il comportamento desiderato è quello di visualizzare i risultati contenenti la frase esatta "cosa è cibo" (prima)

  2. Solo l'ultima parola nella query è evidenziata e voglio evidenziare tutte le parole

Comportamento desiderato: la risposta giusta viene visualizzata in alto, indipendentemente dalla sua posizione nel database.

Il mio codice attuale è così:

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>";
  }
}

13
2018-01-14 12:55


origine


risposte:


Aggiungi un campo ordinabile alla tua query

Per prima cosa dobbiamo semplificare il tuo problema

Il tuo problema può essere considerato una semplice corrispondenza di parole chiave, in cui i risultati principali devono corrispondere a tutte le parole chiave inserite.

Una ricerca per: some search text dovrebbe restituire tutti i risultati contenenti una di quelle parole ['some', 'search', 'text'], con risultati nella corrispondenza in alto esattamente come inserito  "some search text".

Ciò significa che dovrai creare un campo aggregato che consenta di ordinare il risultato in base a una corrispondenza. L'unico modo che conosco per farlo, senza refactoring di dati e / o codice, è con a MySql Case dichiarazione.

La tua domanda semplificata

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

Caso [corrispondenza completa] e Ordina

Quello che dobbiamo costruire è una query che assomiglia un po 'a questo:

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

Regolazione del codice

// 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;

Cosa fa questo?

Abbiamo aggiunto un nuovo campo all'istruzione SELECT, fulltext. Quando una domanda o una risposta contiene esattamente la ricerca completa, questo campo sarà 1, altrimenti 0. Quindi semplicemente ordinare in questo campo.

evidenziando

Per quanto riguarda il problema di evidenziazione, stai solo sostituendo $text che è impostato in un ciclo su ogni parola in mainSearch. Quindi, sarà solo l'ultima parola nel set. Invece, dovrai fare un ciclo simile qui.

Il tuo codice

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

Aggiustato

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

10
2018-01-18 18:59



Puoi utilizzare le API di Google NLP per rilevare parole che sono solo connnector e parole che sono nounds e hanno rilevanza, in modo che la query che invii al database ignori parole come "what" o "is" e in questo modo puoi fornire un'esperienza molto migliore per i tuoi utenti. ci sono anche altri strumenti come NLTK et al che possono anche essere usati per rendere le query più intelligenti.


3
2018-01-23 06:13



Per motivi di prestazioni, dovresti usare REGEXP invece di più LIKE Istruzioni. L'ordine può essere fatto usando un semplice ORDER BY istruzioni come quella qui sotto:

$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;";

L'evidenziazione può essere fatta facilmente usando preg_replace

 preg_replace("/($pattern)/",
       "<span style='font-weight: bold; color: #1a0dab;'>$1</span>",
       $row['answer']);

2
2018-01-24 16:48



Per prima cosa esegui la query sottostante nel tuo database una volta.

ALTER TABLE  questions  ADD FULLTEXT(question, answer);

Quindi utilizzare sotto query per la ricerca

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

}

Questa è la ricerca full text che ti dà risultati in base alla pertinenza e può essere organizzata in ordine decrescente per mostrare la ricerca al primo punto che è più affidabile per la ricerca.


1
2018-01-23 11:59



Dato ciò test tavolo

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');

le tue query finali dovrebbero assomigliare a questo

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

Puoi testare tutte le query sopra DB Fiddle

Per costruire questo tipo di query e dato che stai usando PDO, il tuo PHP il codice dovrebbe assomigliare a questo.

...
// 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();
...

0
2018-01-25 01:19