Algorithme pour trouver des articles avec un texte similaire

j'ai beaucoup d'articles dans une base de données (avec titre,texte), je suis à la recherche d'un algorithme pour trouver les X articles les plus similaires, quelque chose comme les" questions liées " de Stack Overflow quand vous posez une question.

j'ai essayé de googler pour cela, mais j'ai seulement trouvé des pages sur d'autres" textes similaires " questions, quelque chose comme comparer chaque article avec tous les autres et de stocker une similitude quelque part. Tout comme "en temps réel" sur un texte que je viens de taper.

Comment?

58
demandé sur Serge Rogatch 2008-10-29 17:16:44

15 réponses

Edit distance n'est pas un candidat probable, car il dépendrait de l'orthographe/l'ordre des mots, et beaucoup plus de calcul coûteux que Will vous amène à croire, compte tenu de la taille et le nombre des documents que vous seriez réellement intéressés à rechercher.

quelque chose comme Lucene est la voie à suivre. Vous indexez tous vos documents, et puis quand vous voulez trouver des documents similaires à un document donné, vous transformez votre document donné en interrogez et cherchez dans l'index. À L'interne, Lucene utilisera tf-idf et un index inversé pour faire en sorte que l'ensemble du processus prenne un temps proportionnel au nombre de documents qui pourraient éventuellement correspondre, et non au nombre total de documents de la collection.

33
répondu Jay Kominek 2008-10-30 23:36:49

Cela dépend de votre définition de semblable.

l'algorithme edit-distance est l'algorithme standard pour les suggestions de dictionnaires (en latin), et peut fonctionner sur des textes entiers. Deux textes sont similaires s'ils ont fondamentalement les mêmes mots (lettres eh) dans le même ordre. Les deux critiques de livres devrait être assez similaire:

1) "C'est un grand livre"

2) "ceux-ci ne sont pas grands livres "

(le nombre de lettres à supprimer, insérer, supprimer ou Modifier pour transformer (2) en (1) est appelé la "distance d'édition".)

pour mettre en œuvre ce que vous voudriez visiter chaque revue programmatically. Ce n'est peut-être pas aussi coûteux que cela en a l'air, et si c'est trop coûteux, vous pourriez faire les comparaisons en tant que tâche de fond et stocker le N-most-similiar dans un champ de base de données lui-même.

une Autre approche consiste à comprendre quelque chose de la structure des langues (latines). Si vous supprimez des mots courts (Non-capitialisés ou cités), et assignez des poids aux mots (ou préfixes) qui sont communs ou uniques, vous pouvez faire une comparaison Bayesianesque. Les deux critiques de livres suivantes pourraient être simiplied et trouver à être similiar:

3) " la Révolution française était bla bla guerre et Paix bla bla France."- >France/French(2) Révolution(1) Guerre(1) Paix (1) (notez qu'un dictionnaire a été utilisé pour combiner la France et le français)

4) "Ce livre est bla bla, une révolution dans la cuisine française."- >France(1) Révolution (1)

pour mettre en œuvre ceci, vous voudriez identifier les 'mots-clés' dans un examen quand il a été créé/mis à jour, et de trouver des revues similaires utiliser ces mots-clés dans la clause où-d'une requête (idéalement 'texte complet' recherche Si la base de données le soutient), avec peut-être un post-traitement des résultats-ensemble pour la notation des candidats trouvés.

livres ont également des catégories-les thrillers mis en France similiar à des études historiques de la France, et ainsi de suite? Les méta-données au-delà du titre et du texte pourraient être utiles pour garder les résultats pertinents.

14
répondu Will 2008-10-29 15:16:37

le tutoriel à ce lien sonne comme il peut être ce dont vous avez besoin. Il est facile à suivre et fonctionne très bien.

Son algorithme récompense à la fois les substrats communs et un ordre commun de ces substrats et devrait donc choisir des titres similaires assez bien.

9
répondu alex77 2008-10-29 14:21:05

je suggère d'indexer vos articles en utilisant Apache Lucene , une bibliothèque de moteur de recherche de texte haute performance, plein-featured entièrement écrit en Java. Il s'agit d'une technologie adaptée à presque toutes les applications nécessitant une recherche en texte intégral, en particulier la plate-forme . Une fois indexé, vous pouvez facilement trouver des articles connexes.

3
répondu Guido 2008-10-29 14:21:56

un algorithme commun utilisé est la " Carte Auto-Organisante . Il s'agit d'un type de réseau neuronal qui catégorisera automatiquement vos articles. Ensuite, vous pouvez simplement trouver l'emplacement actuel de l'article est à la carte et tous les articles près de lui sont liés. La partie importante de l'algorithme est la façon dont vous vectoriel quantize votre entrée . Il y a plusieurs façons de faire avec le texte. Vous pouvez hachez votre document / titre, vous pouvez compter les mots et utilisez - le comme vecteur dimensionnel, etc. J'espère que ça vous aidera, même si j'ai ouvert une boîte de Pandore pour vous d'un voyage sans fin à AI.

2
répondu mempko 2008-10-29 15:00:38

ainsi la comparaison se fait seulement sur le titre, pas sur le corps du texte de la question, donc seulement sur des chaînes plutôt courtes.

Vous pouvez utiliser leur algorithme (aucune idée de à quoi il ressemble) sur le titre de l'article et les mots clés. Si vous avez plus de temps processeur à brûler, également sur les résumés de vos articles.

1
répondu Treb 2008-10-29 14:22:57

appuie la suggestion de Lucene pour le texte intégral, mais notez que java n'est pas une exigence; un port .NET est disponible . Voir aussi la page principale de Lucene pour des liens vers d'autres projets, y compris Lucy, a C port .

1
répondu b w 2008-10-29 14:31:01

peut-être que ce que vous cherchez est quelque chose qui fait paraphraser . Je n'ai qu'une connaissance superficielle de cela, mais paraphraser est un traitement du langage naturel concept pour déterminer si deux passages du texte en fait signifie la même chose - bien qu'ils puissent utiliser des mots tout à fait différents.

malheureusement, Je ne connais pas d'outils qui vous permettent de le faire (bien que je serais intéressé par trouver un)

1
répondu Vinnie 2008-10-29 14:33:42

vous pouvez utiliser SQL Server Full-text index pour obtenir la comparaison intelligente, je crois que C'est ainsi utiliser un appel ajax, qui fait une requête pour retourner les questions similaires.

Quelles technologies utilisez-vous?

0
répondu Mitchel Sellers 2008-10-29 14:19:54

si vous cherchez des mots qui blessent de la même façon, vous pouvez convertir en soundex et les mots soundex pour correspondre ... a travaillé pour moi

0
répondu spacemonkeys 2008-10-29 14:50:35

j'ai essayé une méthode mais aucune ne fonctionne bien.On peut obtenir un résultat relativement satifié comme celui-ci: Tout d'abord: obtenez un code Google SimHash pour chaque paragraphe de tout le texte et de le stocker dans la base de données. Second: Index pour le code SimHash. Troisièmement: traitez votre texte pour être comparé comme ci-dessus, obtenez un code SimHash et recherchez tout le texte par index SimHash qui à part forment une distance de martelage comme 5-10. Comparez ensuite la similitude avec le vecteur terme. Cela peut fonctionner pour le big data.

0
répondu Luna_one 2013-07-22 06:47:21
0
répondu alex 2016-03-11 06:34:44

le lien dans la réponse de @alex77 pointe vers un Coefficient Sorensen-Dice qui a été découvert indépendamment par l'auteur de cet article - l'article est très bien écrit et vaut la peine d'être lu.

j'ai fini par utiliser ce coefficient pour mes propres besoins. Toutefois, le coefficient initial peut donner des résultats erronés lorsqu'il s'agit de

."
  • trois paires de mots qui contiennent une faute d'orthographe, par exemple [and,amd] et
  • paires de mots à trois lettres qui sont des anagrammes, p.ex. [and,dan]

dans le premier cas, Dice déclare par erreur un coefficient de zéro, tandis que dans le second cas, le coefficient est de 0,5, ce qui est anormalement élevé.

une amélioration a été suggéré qui dans son essence consiste à prendre le premier et le dernier caractère du mot et de créer un bigramme supplémentaire.

à mon avis, l'amélioration n'est vraiment nécessaire que pour les mots de trois lettres - en d'autres termes, les autres bigrammes ont un effet tampon qui couvre le problème. Mon code qui met en œuvre cette amélioration est donné ci-dessous.

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>

Note la délibérer faute d'orthographe dans le dernier exemple: abraca dabra vs abraca badra . Bien qu'aucune correction bigramme supplémentaire ne soit appliquée, le coefficient rapporté est de 0,9. Avec la correction, il aurait été de 0,91.

avec un peu de chance, cela aidera d'autres qui courent dans ce fil.

0
répondu DroidOS 2017-02-27 09:44:17

avec un exemple de texte, ce programme répertorie les textes du dépôt Classés par similarité: simple implémentation de sac de mots en C++ . L'algorithme est linéaire dans la longueur totale du texte échantillon et des textes du dépôt. De plus, le programme est multi-threadé pour traiter les textes du dépôt en parallèle.

Voici l'algorithme de base:

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
répondu Serge Rogatch 2018-09-03 15:51:26

la façon la plus simple et la plus rapide de comparer la similitude entre les abrégés est probablement en utilisant le concept set. D'abord, convertissez les textes abstraits en un ensemble de mots. Ensuite, vérifiez combien chaque ensemble se chevauche. La fonctionnalité de jeu de Python vient très Main exécutant cette tâche. Vous seriez surpris de voir à quel point cette méthode se compare à ces "documents similaires/connexes" options là-bas fournis par GScholar, annonces, WOS ou Scopus.

-1
répondu Gökhan Sever 2015-04-18 20:04:57