Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie finde ich ähnliche Ergebnisse und sortiere nach Ähnlichkeit?

Ich habe herausgefunden, dass die Levenshtein-Distanz gut sein kann, wenn Sie eine vollständige Zeichenfolge gegen eine andere vollständige Zeichenfolge suchen, aber wenn Sie nach Schlüsselwörtern innerhalb einer Zeichenfolge suchen, gibt diese Methode (manchmal) nicht die gewünschten Ergebnisse zurück. Außerdem ist die SOUNDEX-Funktion nicht für andere Sprachen als Englisch geeignet, also ziemlich eingeschränkt. Sie könnten mit LIKE davonkommen, aber es ist wirklich für einfache Suchen. Vielleicht möchten Sie sich andere Suchmethoden ansehen, um herauszufinden, was Sie erreichen möchten. Zum Beispiel:

Sie können Lucene verwenden als Suchbasis für Ihre Projekte. Es ist in den meisten wichtigen Programmiersprachen implementiert und sehr schnell und vielseitig. Diese Methode ist wahrscheinlich die beste, da sie nicht nur nach Teilzeichenfolgen sucht, sondern auch nach Buchstabentransposition, Präfixen und Suffixen (alles kombiniert). Sie müssen jedoch einen separaten Index führen (CRON zu verwenden, um ihn von Zeit zu Zeit von einem unabhängigen Skript aus zu aktualisieren, funktioniert jedoch).

Oder, wenn Sie eine MySQL-Lösung wollen, die Volltextfunktionalität ist ziemlich gut und sicherlich schneller als eine gespeicherte Prozedur. Wenn Ihre Tabellen nicht MyISAM sind, können Sie eine temporäre Tabelle erstellen und dann Ihre Volltextsuche durchführen:

CREATE TABLE IF NOT EXISTS `tests`.`data_table` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(2000) CHARACTER SET latin1 NOT NULL,
  `description` text CHARACTER SET latin1 NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1 ;

Verwenden Sie einen Datengenerator um zufällige Daten zu generieren, wenn Sie sich nicht die Mühe machen wollen, sie selbst zu erstellen ...

** HINWEIS ** :Der Spaltentyp sollte latin1_bin sein um mit latin1 eine Suche mit Berücksichtigung der Groß- und Kleinschreibung anstelle der Berücksichtigung der Groß-/Kleinschreibung durchzuführen . Für Unicode-Strings würde ich utf8_bin empfehlen für case sensitive und utf8_general_ci für Suchen ohne Berücksichtigung der Groß-/Kleinschreibung.

DROP TABLE IF EXISTS `tests`.`data_table_temp`;
CREATE TEMPORARY TABLE `tests`.`data_table_temp`
   SELECT * FROM `tests`.`data_table`;

ALTER TABLE `tests`.`data_table_temp`  ENGINE = MYISAM;

ALTER TABLE `tests`.`data_table_temp` ADD FULLTEXT `FTK_title_description` (
  `title` ,
  `description`
);

SELECT *,
       MATCH (`title`,`description`)
       AGAINST ('+so* +nullam lorem' IN BOOLEAN MODE) as `score`
  FROM `tests`.`data_table_temp`
 WHERE MATCH (`title`,`description`)
       AGAINST ('+so* +nullam lorem' IN BOOLEAN MODE)
 ORDER BY `score` DESC;

DROP TABLE `tests`.`data_table_temp`;

Lesen Sie mehr darüber auf der MySQL-API-Referenzseite

Der Nachteil dabei ist, dass es nicht nach Buchstabenumsetzungen oder "ähnlichen, klingt wie" Wörtern sucht.

** AKTUALISIEREN **

Wenn Sie Lucene für Ihre Suche verwenden, müssen Sie einfach einen Cron-Job erstellen (alle Webhoster haben dieses "Feature"), wobei dieser Job einfach ein PHP-Skript ausführt (z. B. "cd /path/to/script; php searchindexer.php" ), wodurch die Indizes aktualisiert werden. Der Grund dafür ist, dass das Indizieren von Tausenden von "Dokumenten" (Zeilen, Daten usw.) einige Sekunden oder sogar Minuten dauern kann, aber dies soll sicherstellen, dass alle Suchen so schnell wie möglich durchgeführt werden. Daher möchten Sie möglicherweise einen Verzögerungsjob erstellen, der vom Server ausgeführt wird. Es kann über Nacht oder in der nächsten Stunde sein, das liegt an Ihnen. Das PHP-Skript sollte in etwa so aussehen:

$indexer = Zend_Search_Lucene::create('/path/to/lucene/data');

Zend_Search_Lucene_Analysis_Analyzer::setDefault(
  // change this option for your need
  new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num_CaseInsensitive()
);

$rowSet = getDataRowSet();  // perform your SQL query to fetch whatever you need to index
foreach ($rowSet as $row) {
   $doc = new Zend_Search_Lucene_Document();
   $doc->addField(Zend_Search_Lucene_Field::text('field1', $row->field1, 'utf-8'))
       ->addField(Zend_Search_Lucene_Field::text('field2', $row->field2, 'utf-8'))
       ->addField(Zend_Search_Lucene_Field::unIndexed('someValue', $someVariable))
       ->addField(Zend_Search_Lucene_Field::unIndexed('someObj', serialize($obj), 'utf-8'))
  ;
  $indexer->addDocument($doc);
}

// ... you can get as many $rowSet as you want and create as many documents
// as you wish... each document doesn't necessarily need the same fields...
// Lucene is pretty flexible on this

$indexer->optimize();  // do this every time you add more data to you indexer...
$indexer->commit();    // finalize the process

Dann suchen Sie im Grunde so (einfache Suche):

$index = Zend_Search_Lucene::open('/path/to/lucene/data');

// same search options
Zend_Search_Lucene_Analysis_Analyzer::setDefault(
   new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num_CaseInsensitive()
);

Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding('utf-8');

$query = 'php +field1:foo';  // search for the word 'php' in any field,
                                 // +search for 'foo' in field 'field1'

$hits = $index->find($query);

$numHits = count($hits);
foreach ($hits as $hit) {
   $score = $hit->score;  // the hit weight
   $field1 = $hit->field1;
   // etc.
}

Hier sind tolle Seiten über Lucene in Java , PHP , und .Net .

Zum Schluss Jede Suchmethode hat ihre eigenen Vor- und Nachteile:

  • Sie erwähnten Sphinx-Suche und es sieht sehr gut aus, solange Sie den Deamon auf Ihrem Webhost zum Laufen bringen können.
  • Zend Lucene benötigt einen Cron-Job, um die Datenbank neu zu indizieren. Obwohl dies für den Benutzer ziemlich transparent ist, bedeutet dies, dass neue Daten (oder gelöschte Daten!) nicht immer mit den Daten in Ihrer Datenbank synchron sind und daher nicht sofort bei der Benutzersuche angezeigt werden.
  • Die MySQL-FULLTEXT-Suche ist gut und schnell, bietet Ihnen aber nicht die ganze Leistung und Flexibilität der ersten beiden.

Bitte zögern Sie nicht zu kommentieren, wenn ich etwas vergessen/verpasst habe.