PHP Suchscript, stehe wiedermal auf der Leitung...

Shadow1701

Ensign
Registriert
Juli 2012
Beiträge
209
Schönen Nachmittag euch allen.

Ich bin gerade mit einem Suchscript beschäftigt welches Dateien durchsuchen soll welche vorher indiziert wurden. Die Datenbank sieht so aus:

Code:
--
-- Tabellenstruktur für Tabelle `searchfiles`
--

CREATE TABLE `searchfiles` (
  `sfid` int(11) NOT NULL,
  `sfcategoryid` int(4) NOT NULL,
  `sffile` longtext COLLATE utf8_german2_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_german2_ci;

-- --------------------------------------------------------

--
-- Tabellenstruktur für Tabelle `searchindex`
--

CREATE TABLE `searchindex` (
  `wordid` int(11) NOT NULL,
  `word` char(255) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

-- --------------------------------------------------------

--
-- Tabellenstruktur für Tabelle `searchmatch`
--

CREATE TABLE `searchmatch` (
  `matchid` int(11) NOT NULL,
  `filecat` int(4) NOT NULL,
  `fileid` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Natürlich gibt es auch Primary, hab das nur abgekürzt....

in SEARCHFILES steht der Pfad zu den TXT und HTML Dateien drinnen.
in SEARCHINDEX stehen alle Wörter welch in den Dateien vorkommen genau EINMAL drinnen. Mit zugeordneter Primärschlüssel ID.
in SEARCHMATCH ist die Information vorhanden welches wort in welcher Datei vorhanden ist.

Die mySQL Abfrage ist diese da:
Code:
SELECT DISTINCT searchfiles.sfid,searchfiles.sfcategoryid,searchfiles.sffile FROM `searchindex` LEFT JOIN `searchmatch` ON (searchindex.wordid=searchmatch.matchid) LEFT JOIN `searchfiles` ON (searchmatch.fileid=searchfiles.sfid) WHERE searchmatch.filecat='0' AND (`word`='Dampflokomotive' OR `word`='Schmalspurbahn');

Das Ergebnis ist jetzt eine Liste mit allen Dateien welche die Wörter "Dampflokomotive" ODER "Schmalspurbahn" enthalten.

Was ich momentan so gar nicht schaffe, ist es eine Liste der Dateien auszugeben, welche die Wörter "Dampflokomotive" UND "Schmalspurbahn" enthalten.

Entweder habe ich hier einen grundlegenden Denkfehler oder wieder eine meiner brühmten Hirnblockaden weil ich es momentan so gar nicht schaffe die SQL Abfrage entsprechend anzupassen.

Kann mir jemand helfen?
 
Unabhängig von SQL:
Wenn du die Menge von "Dateien mit Wörter A und B" nicht findest, dann kannst du dich evtl mit den beiden Mengen "Dateien mit Wort A" und "Dateien mit Wort B" ans Ziel hangeln... die gesuchten Dateien müssen in beiden Mengen vorkommen.
 
Bedenke, dass du in SQL durch WHERE immer nur komplette Tabellenzeilen behältst oder verwirfst.

Also was macht dein Skript? Exemplarisch:

1. RES_1 = SELECT wordid FROM searchindex WHERE word IN ('wort1', 'wort2')
In RES_1 stehen jetzt alle wordids, auf die die Suche zugetroffen hat.

2. RES_2 = SELECT fileid FROM searchmatch WHERE matchid IN (RES_1)
In RES_2 stehen jetzt alle fileids, wo irgendeine der wordids aus RES_1 gefunden wurde.

Heißt: Manche fileids stehen jetzt 1x in RES_2, weil nur 1 Wort darin vorkam, und manche fileids stehen doppelt drin, weil beide Worte drin vorkamen.

Nun müsstest du also erst mal zählen, wie oft welche fileid in RES_2 auftaucht:
3. RES_3 = SELECT fileid, COUNT(*) FROM RES_2 GROUP BY fileid
In RES_3 stehen nun die gruppierten fileids zusammen mit ihrer Anzahl.

Jetzt musst du das Ergebnis noch filtern und nur die Ergebnisse behalten wo Anzahl = 2:
4. RES_4 = SELECT fileid FROM RES_3 WHERE COUNT(*) = 2

Das lässt sich natürlich auch abkürzen und direkt mit in's GROUP BY integrieren:
3. RES_3 = SELECT fileid, COUNT() FROM RES_2 GROUP BY fileid HAVING COUNT() = 2
(Aus einem mir unerfindlichen Grund werden die Sternchen beim COUNT immer entfernt, wenn ich speichere :confused_alt: Denk sie dir einfach dazu)
Dann stehen in RES_3 nur noch die fileids, die 2 mal in RES_2 standen.

Und natürlich lässt sich der gesamte Kram auch in ein einzelnes SQL Statement packen. Aber das ist deine Aufgabe.
 
Zuletzt bearbeitet:
@benneq danke für die detaillierte Antwort. Ich habe es in ein einzelnes SQL Statement gepackt und es funktioniert so wie es soll. Super :)
 
Zurück
Oben