Hulp bij search query

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Bryan De Baar

Bryan De Baar

17/06/2020 13:43:38
Quote Anchor link
Beste leden,


Ik kamp met een probleem in mijn search query en had graag wat hulp gehad.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
<?php
$q
=  $_POST['search'];
    $query = "
        SELECT p.ID, p.post_title, m.meta_id, m.meta_key, m.meta_value
        FROM wp_posts p
        LEFT JOIN wp_postmeta m ON (m.post_id = p.ID)
        WHERE EXISTS (SELECT 1 FROM wp_posts WHERE post_title LIKE '%$q%' AND ID = p.ID)
        AND EXISTS (SELECT 1 FROM wp_posts WHERE post_type='product' AND ID = p.ID)
        OR EXISTS (SELECT 1 FROM wp_postmeta WHERE meta_key = '_sku' AND meta_value LIKE '%$q%' AND post_id = p.ID)
        ORDER BY p.ID, m.meta_id
    "
;
?>


In de tabel wp_post word gezocht in de kolom post_title en in de kolom ID.
Dan is er nog de conditie als post_type is gelijk aan product.
Maar er word ook gekeken in de kolom _sku van tabel wp_postmeta.

Het probleem waar ik mee zit is dat er niet goed op de losse worden word gezocht.

Stel dat er een artikel is: Voetbal schoenen rood met zwart

Als ik vervolgens een post geef met de waarde voetbal rood dan schijnt er geen artikel te zijn.
Maar geef ik de waarde Voetbal schoenen rood dan krijg ik wel de juiste producten.

In principe moeten alle woorden die in de string zitten van links naar rechts, rechts naar links een resultaat geven.
Dus dat je ook resultaat krijgt op rood voetbal
 
PHP hulp

PHP hulp

26/09/2020 01:00:58
 
Rob Doemaarwat

Rob Doemaarwat

17/06/2020 14:35:44
Quote Anchor link
In plaats van op de hele $q te zoeken moet je de $q dan splitsen in woorden. Vervolgens ga je dan alle posts zoeken waar één van die woorden in voorkomt. Dat zijn er natuurlijk weer heel veel, dus vervolgens pak je alleen die posts (de top-zoveel) waarin de meeste woorden voorkomen. En als je helemaal Google wilt spelen kun je ook nog kijken hoe dicht de woorden bij elkaar staan (dichterbij is beter).
 
Bryan De Baar

Bryan De Baar

17/06/2020 16:55:37
Quote Anchor link
Hoi Rob,

Dus eigenlijk de string opsplitsen met explode?
En deze door de query halen?
 
Rob Doemaarwat

Rob Doemaarwat

17/06/2020 18:16:35
Quote Anchor link
Zelf zou ik
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
$words = preg_split('/\\W+/',$q);
doen. En dan voor elke woord de query aanvullen met wat je hierboven voor enkel de $q gedaan hebt (let even op dat je AND en OR's goed gaan; gebruik evt. extra haakjes om eea duidelijk te houden).

En dan dus nog een soort "score" berekenen. Dit kun je in SQL doen, of via SQL alleende grove filtering, en de score in PHP berekenen (ligt er een beetje aan wat het makkelijkst is, en hoeveel resultaten je verwacht - heb je 1000 of 1000000 posts).
 
Bryan De Baar

Bryan De Baar

18/06/2020 13:21:37
Quote Anchor link
Hi Rob,


Als ik de preg_split gebruik is het dan de bedoeling om een foreach aan te maken waarin de query staat?
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

$words
= preg_split('/\W+/',$_POST['search']);
foreach($words as $word){
    $query = "
        SELECT p.ID, p.post_title, m.meta_id, m.meta_key, m.meta_value
        FROM wp_posts p
        LEFT JOIN wp_postmeta m ON (m.post_id = p.ID)
        WHERE EXISTS (SELECT 1 FROM wp_posts WHERE post_title LIKE '%$word%' AND ID = p.ID)
        AND EXISTS (SELECT 1 FROM wp_posts WHERE post_type='product' AND ID = p.ID)
        OR EXISTS (SELECT 1 FROM wp_postmeta WHERE meta_key = '_sku' AND meta_value LIKE '%$word%' AND post_id = p.ID)
        ORDER BY p.ID, m.meta_id
    "
;

while($row = mysqli_fetch_assoc($result)){    
//doe wat met je resultaten
//kan ik hier een score bereken voor de resultaten zoals je aangaf?

}
}



?>
 
Rob Doemaarwat

Rob Doemaarwat

18/06/2020 13:39:58
Quote Anchor link
Nee, uiteindelijk moet een soort SQL krijgen in de vorm:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
//stel $words = ['aap','noot','mies']
select * from tabel t
where (t.titel like '%aap%') or (t.meta like '%aap%')
   or (t.titel like '%noot%') or (t.meta like '%noot%')
   or (t.titel like '%mies%') or (t.meta like '%mies%')

Vervolgens ga je daar "de beste" uit zoeken. Dat kan met PHP, of in SQL bijvoorbeeld:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
order by if(t.titel like '%aap%',2,0) + if(t.meta like '%aap%',1,0) +
         if(t.titel like '%noot%',2,0) + if(t.meta like '%noot%',1,0) +
         if(t.titel like '%mies%',2,0) + if(t.meta like '%mies%',1,0) desc
limit 10

- 2 punten als het woord in de titel voorkomt
- 1 punt als het woord in de meta staat
- de post met de meeste punten bovenaan
- limiteer tot 10
(maar dit alles dus naar eigen inzicht)

En uiteraard is jouw situatie nog net iets complexer ;-p

Bonus
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
if(t.titel like '%aap%',2,0) + if(t.meta like '%aap%',1,0) + if(t.meta = 'aap',5,0)

= een exacte match op een woord extra punten (5) geven.

Je zou ook eens naar full text search kunnen kijken. Maar daar moet je vaak wel je DB op inrichten / voor aanpassen.
 
Jop B

Jop B

19/06/2020 01:14:16
Quote Anchor link
Kan die niet simple gewoon met WHERE MATCH(kolommen) AGAINST(sleutelwoorden) werken?
 
Bryan De Baar

Bryan De Baar

20/06/2020 21:25:50
Quote Anchor link
Met wat dingen te proberen ben ik al een stuk verder.
@rob het score systeem is inderdaad erg handig.
Ik ben begonnen met een simpele query met dit als resultaat
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
$connection
    = mysqli_connect('host', 'user', 'password', 'database');

$searchstrg = $_POST['search'];

$words = explode(" ", $searchstrg);
$totalwords = count($words);

$query = "SELECT * FROM wp_posts WHERE post_type='product' AND (post_title LIKE '%$words[0]%' OR post_content LIKE '%$words[0]%')";
$ordercondition = "IF(post_title LIKE '%$words[0]%',2,0) + IF(post_content LIKE '%$words[0]%',1,0)";


if($totalwords > 1){
    for($i=1;$i<$totalwords;$i++) {
        $query .= "UNION SELECT * FROM wp_posts WHERE post_type='product' AND (post_title LIKE '%$words[$i]%' OR post_content LIKE '%$words[$i]%')";
        $ordercondition .= "+ IF(post_title LIKE '%$words[$i]%',2,0) + IF(post_content LIKE '%$words[$i]%',1,0)";
    }
}



$query .= 'ORDER BY '.$ordercondition.' DESC LIMIT 10';

$result    = mysqli_query($connection, $query);
while($row = mysqli_fetch_assoc($result)){    
    echo $row['post_title'];
}

?>


Dit levert de gewenste resultaten op maar nog zonder de 2e tabel.

Ik ben begonnen hieraan maar loop toch nog vast.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?php
$connection
    = mysqli_connect('host', 'user', 'password', 'database');

$searchstrg = $_POST['search'];

$words = explode(" ", $searchstrg);
$totalwords = count($words);

$query = "
    SELECT p.ID, p.post_title, pm.meta_key
    FROM wp_posts p
    LEFT JOIN wp_postmeta pm ON (pm.post_id = p.ID)
    WHERE post_type='product' AND (post_title LIKE '%$words[0]%' OR post_content LIKE '%$words[0]%')"
;
$ordercondition = "IF(post_title LIKE '%$words[0]%',2,0) + IF(post_content LIKE '%$words[0]%',1,0)";


if($totalwords > 1){
    for($i=1;$i<$totalwords;$i++) {
        $query .= "UNION SELECT * FROM wp_posts WHERE post_type='product' AND (post_title LIKE '%$words[$i]%' OR post_content LIKE '%$words[$i]%')";
        $ordercondition .= "+ IF(post_title LIKE '%$words[$i]%',2,0) + IF(post_content LIKE '%$words[$i]%',1,0)";
    }
}



$query .= 'ORDER BY '.$ordercondition.' DESC LIMIT 10';

$result    = mysqli_query($connection, $query);
?>
<table><?php
while($row = mysqli_fetch_assoc($result)){    
    if($row['ID'] !== $existid){
        echo '<tr><td>'.$row['ID'].'</td></tr>';
    }

    
    if ($row['post_title'] !== $existtitle) {  
        echo '<tr><td>'.$row['post_title'].'</td></tr>';
    }

    echo '<tr><td>'.$row['meta_key'].'</td></tr>';
    $existtitle    = $row['post_title'];
    $existid     = $row['ID'];
}

?>

</table>



De limit had ik graag alleen op de wp_post tabel gehad zodat er 10 producten geladen worden met wel alle meta_keys, want deze worden nu allemaal opgeteld en dan is je limit zo bereikt

Het zoeken naar de _sku wil ik ook graag nog inbouwen en dan ben ik helemaal blij :)
Gewijzigd op 20/06/2020 21:35:28 door Bryan De Baar
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.