it-swarm.com.de

Algorithmus zum Auffinden von Artikeln mit ähnlichem Text

Ich habe viele Artikel in einer Datenbank (mit Titel, Text). Ich suche nach einem Algorithmus, um die X-ähnlichsten Artikel zu finden, etwa die "Verwandte Fragen" von Stack Overflow, wenn Sie eine Frage stellen. 

Ich habe versucht, googeln zu lassen, habe aber nur Seiten zu anderen "ähnlichen Text" -Problemen gefunden, zum Beispiel, indem man jeden Artikel mit allen anderen vergleicht und irgendwo eine Ähnlichkeit speichert. SO macht dies in "Echtzeit" für Text, den ich gerade eingegeben habe.

Wie?

58

Entfernung bearbeiten ist kein wahrscheinlicher Kandidat, da es von der Rechtschreibung/der Wortreihenfolge abhängt und viel rechenintensiver ist, als Will Sie glauben lässt, wenn man die Größe und Anzahl der Dokumente bedenkt, die Sie tatsächlich wären interessiert an der Suche.

So etwas wie Lucene ist der Weg zu gehen. Sie indizieren alle Ihre Dokumente. Wenn Sie Dokumente suchen möchten, die einem bestimmten Dokument ähneln, wandeln Sie Ihr Dokument in eine Abfrage um und durchsuchen den Index. Intern verwendet Lucene tf-idf und einen invertierten Index , damit der gesamte Prozess eine Zeit proportional zur Anzahl der Dokumente benötigt, die möglicherweise übereinstimmen, und nicht der Gesamtzahl der Dokumente in der Sammlung .

33
Jay Kominek

Es hängt von Ihrer Definition von Ähnlichem ab.

Der edit-distance -Algorithmus ist der Standardalgorithmus für Wörterbuchvorschläge (in lateinischer Sprache) und kann ganze Texte bearbeiten. Zwei Texte sind ähnlich, wenn sie im Wesentlichen die gleichen Wörter (wie Buchstaben) in derselben Reihenfolge haben. Die folgenden zwei Buchbesprechungen wären also ziemlich ähnlich:

1) "Das ist ein tolles Buch"

2) "Das sind keine großartigen Bücher"

(Die Anzahl der Buchstaben, die entfernt, eingefügt, gelöscht oder geändert werden sollen, um (2) in (1) zu verwandeln, wird als "Bearbeitungsentfernung" bezeichnet.)

Um dies zu implementieren, möchten Sie jeden Bericht programmatisch besuchen. Dies ist möglicherweise nicht so teuer, wie es sich anhört, und wenn es zu teuer ist, könnten Sie die Vergleiche als Hintergrundaufgabe durchführen und das n-most-ähnliche in einem Datenbankfeld selbst speichern.

Ein anderer Ansatz besteht darin, etwas über die Struktur von (lateinischen) Sprachen zu verstehen. Wenn Sie kurze (nicht kapitialisierte oder zitierte) Wörter entfernen und Wörtern (oder Präfixen), die häufig oder eindeutig sind, Gewichte zuweisen, können Sie einen Vergleich mit Bayesianesque durchführen. Die beiden folgenden Buchbesprechungen werden möglicherweise vereinfacht und als ähnlich angesehen:

3) "Die französische Revolution war bla bla, Krieg und Frieden bla bla, Frankreich." -> Frankreich/Französisch (2) Revolution (1) Krieg (1) Frieden (1) (Beachten Sie, dass ein Wörterbuch verwendet wurde, um Frankreich und Französisch zu kombinieren).

4) "Dieses Buch ist eine Revolution in der französischen Küche." -> Frankreich (1) Revolution (1)

Um dies zu implementieren, möchten Sie die "Schlüsselwörter" in einer Überprüfung identifizieren, wenn sie erstellt/aktualisiert wurde. Um ähnliche Bewertungen zu finden, verwenden Sie diese Schlüsselwörter in der where-Klausel einer Abfrage (idealerweise Volltextsuche, wenn die Datenbank dies unterstützt.) ), möglicherweise mit einer Nachbearbeitung der Ergebnismenge zur Bewertung der gefundenen Kandidaten.

Bücher haben auch Kategorien - sind Thriller in Frankreich ähnlich zu historischen Studien in Frankreich und so weiter? Metadaten über Titel und Text hinaus können hilfreich sein, um die Ergebnisse relevant zu halten.

14
Will

Das Tutorial zu diesem link hört sich an, als könnte es das sein, was Sie brauchen. Es ist leicht zu folgen und funktioniert sehr gut. 

Sein Algorithmus belohnt sowohl allgemeine Unterzeichenfolgen als auch eine gemeinsame Anordnung dieser Teilzeichenfolgen und sollte ähnliche Titel recht gut herausgreifen.

9
alex77

Ich schlage vor, Ihre Artikel zu indexieren, indem Sie Apache Lucene , eine vollständig in Java geschriebene, voll funktionsfähige Textsuchmaschinen-Bibliothek mit vollem Funktionsumfang verwenden. Diese Technologie eignet sich für nahezu jede Anwendung, die eine Volltextsuche erfordert, insbesondere plattformübergreifend. Nach der Indizierung können Sie leicht verwandte Artikel finden.

3
Guido

Ein gängiger Algorithmus ist die selbstorganisierende Karte ..__, eine Art neuronales Netzwerk, das Ihre Artikel automatisch kategorisiert. Dann können Sie einfach den Ort finden, an dem sich ein aktueller Artikel in der Karte befindet, und alle Artikel in der Nähe davon sind miteinander verbunden. Der wichtige Teil des Algorithmus ist, wie Sie Vektorquantisieren Sie Ihre Eingabe . Es gibt mehrere Möglichkeiten, mit Text umzugehen. Sie können Ihr Dokument/Ihren Titel mit einem Hash versehen, Sie können Wörter zählen und diese als n-dimensionalen Vektor verwenden. Hoffen Sie, dass dies hilft, auch wenn ich Ihnen vielleicht eine Büchse der Pandora für eine endlose Reise in der KI geöffnet habe.

2
mempko

Der Vergleich erfolgt also nur über den Titel, nicht über den Haupttext der Frage, also nur über eher kurze Zeichenfolgen.

Sie können ihren Algorithmus (keine Ahnung, wie er aussieht) für den Artikeltitel und die Schlüsselwörter verwenden. Wenn Sie mehr CPU-Zeit zum Brennen haben, auch für die Abstracts Ihrer Artikel.

1
Treb

Weiterleitung des Lucene-Vorschlags für Volltext, beachten Sie jedoch, dass Java nicht erforderlich ist. ein .NET-Port ist verfügbar . Siehe auch die main Lucene-Seite für Links zu anderen Projekten, einschließlich Lucy, einem C-Port .

1
b w

Vielleicht ist das, wonach Sie suchen, etwas, das paraphrasieren tut. Ich habe nur flüchtiges Wissen darüber, aber Umschreiben ist ein natürliche Sprachverarbeitung Konzept, um zu bestimmen, ob zwei Textpassagen tatsächlich bedeuten dasselbe bedeuten - obwohl sie ganz andere Wörter verwenden können.

Leider kenne ich keine Tools, mit denen Sie dies tun können (obwohl ich daran interessiert wäre, eines zu finden)

1
Vinnie

Wenn Sie nach Wörtern suchen, die sich genauso verletzen, könnten Sie zu Soundex konvertieren, und die Soundex-Wörter passen für mich zusammen

0
spacemonkeys

Bei einem Beispieltext listet dieses Programm die Repository-Texte nach Ähnlichkeit sortiert auf: einfache Implementierung eines Beutels Wörter in C++ . Der Algorithmus ist in der Gesamtlänge des Beispieltexts und der Repository-Texte linear. Außerdem ist das Programm multithreaded, um Repository-Texte parallel zu verarbeiten.

Hier ist der Kernalgorithmus:

class Statistics {
  std::unordered_map<std::string, int64_t> _counts;
  int64_t _totWords;

  void process(std::string& token);
public:
  explicit Statistics(const std::string& text);

  double Dist(const Statistics& fellow) const;

  bool IsEmpty() const { return _totWords == 0; }
};

namespace {
  const std::string gPunctStr = ".,;:!?";
  const std::unordered_set<char> gPunctSet(gPunctStr.begin(), gPunctStr.end());
}

Statistics::Statistics(const std::string& text) {
  std::string lastToken;
  for (size_t i = 0; i < text.size(); i++) {
    int ch = static_cast<uint8_t>(text[i]);
    if (!isspace(ch)) {
      lastToken.Push_back(tolower(ch));
      continue;
    }
    process(lastToken);
  }
  process(lastToken);
}

void Statistics::process(std::string& token) {
  do {
    if (token.size() == 0) {
      break;
    }
    if (gPunctSet.find(token.back()) != gPunctSet.end()) {
      token.pop_back();
    }
  } while (false);
  if (token.size() != 0) {
    auto it = _counts.find(token);
    if (it == _counts.end()) {
      _counts.emplace(token, 1);
    }
    else {
      it->second++;
    }
    _totWords++;
    token.clear();
  }
}

double Statistics::Dist(const Statistics& fellow) const {
  double sum = 0;
  for (const auto& wordInfo : _counts) {
    const std::string wordText = wordInfo.first;
    const double freq = double(wordInfo.second) / _totWords;
    auto it = fellow._counts.find(wordText);
    double fellowFreq;
    if (it == fellow._counts.end()) {
      fellowFreq = 0;
    }
    else {
      fellowFreq = double(it->second) / fellow._totWords;
    }
    const double d = freq - fellowFreq;
    sum += d * d;
  }
  return std::sqrt(sum);
}
0
Serge Rogatch

Sie können den SQL Server-Volltextindex verwenden, um den intelligenten Vergleich zu erhalten. Ich glaube, dass SO einen Ajax-Aufruf verwendet, der eine Abfrage ausführt, um ähnliche Fragen zurückzugeben.

Welche Technologien setzen Sie ein?

0
Mitchel Sellers

Der Link in der Antwort von @ alex77 weist auf den Sorensen-Dice-Koeffizienten hin, der vom Autor dieses Artikels unabhängig entdeckt wurde - der Artikel ist sehr gut geschrieben und lohnt sich zu lesen.

Ich habe diesen Koeffizienten für meine eigenen Bedürfnisse verwendet. Der ursprüngliche Koeffizient kann jedoch zu falschen Ergebnissen führen 

  • wortpaare mit drei Buchstaben, die einen Rechtschreibfehler enthalten, z. [and,AMD] und
  • wortpaare mit drei Buchstaben, die Anagramme sind, z. [and,dan]

Im ersten Fall meldet Dice fälschlicherweise einen Koeffizienten von Null, während im zweiten Fall der Koeffizient mit 0,5 ansteigt, was irreführend hoch ist.

Eine Verbesserung wurde vorgeschlagen die im Wesentlichen darin besteht, den ersten und den letzten Buchstaben des Wortes zu nehmen und einen zusätzlichen Bigramm zu schaffen.

Meines Erachtens ist die Verbesserung wirklich nur für Wörter mit 3 Buchstaben erforderlich - in längeren Worten haben die anderen Bigramme einen Pufferungseffekt, der das Problem überdeckt ... Mein Code, der diese Verbesserung implementiert, ist unten angegeben.

function wordPairCount(Word)
{
 var i,rslt = [],len = Word.length - 1;
 for(i=0;i < len;i++) rslt.Push(Word.substr(i,2));
 if (2 == len) rslt.Push(Word[0] + Word[len]);
 return rslt;
}

function pairCount(arr)
{
 var i,rslt = [];
 arr = arr.toLowerCase().split(' ');
 for(i=0;i < arr.length;i++) rslt = rslt.concat(wordPairCount(arr[i]));
 return rslt;
}

function commonCount(a,b)
{
 var t;
 if (b.length > a.length) t = b, b = a, a = t; 
 t = a.filter(function (e){return b.indexOf(e) > -1;});
 return t.length;
}

function myDice(a,b)
{
 var bigrams = [],
 aPairs = pairCount(a),
 bPairs = pairCount(b);
 debugger;
 var isct = commonCount(aPairs,bPairs);
 return 2*commonCount(aPairs,bPairs)/(aPairs.length + bPairs.length); 
}

$('#rslt1').text(myDice('WEB Applications','PHP Web Application'));
$('#rslt2').text(myDice('And','Dan'));
$('#rslt3').text(myDice('and','AMD'));
$('#rslt4').text(myDice('abracadabra','abracabadra'));
*{font-family:arial;}
table
{
 width:80%;
 margin:auto;
 border:1px solid silver;
}

thead > tr > td
{
 font-weight:bold;
 text-align:center;
 background-color:aqua;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<table>
<thead>
<tr>
<td>Phrase 1</td>
<td>Phrase 2</td>
<td>Dice</td>
</tr>
<thead>
<tbody>
<tr>
<td>WEB Applications</td>
<td>PHP Web Application</td>
<td id='rslt1'></td>
</tr>
<tr>
<td>And</td>
<td>Dan</td>
<td id='rslt2'></td>
</tr>
<tr>
<td>and</td>
<td>AMD</td>
<td id='rslt3'></td>
</tr>
<tr>
<td>abracadabra</td>
<td>abracabadra</td>
<td id='rslt4'></td>
</tr>
</tbody>
</table>

Beachten Sie den absichtlichen Rechtschreibfehler im letzten Beispiel: abracadabra vs abracabadra. Obwohl keine zusätzliche Bigrammkorrektur angewendet wird, beträgt der angegebene Koeffizient 0,9. Bei der Korrektur wären es 0,91 gewesen.

Hoffentlich hilft das anderen, die auf diesen Thread stoßen.

0
DroidOS

Ich habe eine Methode ausprobiert, aber keine funktioniert gut. Eine kann ein relativ zufriedenes Ergebnis wie folgt ergeben: Erstens: Holen Sie einen Google SimHash-Code für jeden Absatz des gesamten Textes und speichern Sie ihn in der Datenbank . Zweitens: Index für den SimHash-Code . Drittens: Verarbeiten Sie den zu vergleichenden Text wie oben, holen Sie sich einen SimHash-Code und durchsuchen Sie den gesamten Text nach dem SimHash-Index, der einen Hamming-Abstand von 5-10 bildet. Vergleichen Sie dann die Similität mit dem Termvektor . Dies kann für Big Data funktionieren.

0
Luna_one

sie können entweder 1) Minhash/LSH https://en.wikipedia.org/wiki/MinHash verwenden.

(Siehe auch: http://infolab.stanford.edu/~ullman/mmds/book.pdf )

oder 

2) kollaboratives Filtern: https://en.wikipedia.org/wiki/Collaborative_filtering

0
alex