Un point Python: adict.has_key(k)
est obsolète dans Python 2.X et a disparu dans Python 3.X. k in adict
en tant qu'expression est disponible depuis Python 2.2; utilisez-le à la place. Ce sera plus rapide (pas d'appel de méthode).
Un point pratique en toute langue: parcourez le dictionnaire plus court.
résultat combiné:
if len(doca_dic) < len(docb_dict):
short_dict, long_dict = doca_dic, docb_dic
else:
short_dict, long_dict = docb_dic, doca_dic
similarity = 0
for x in short_dict:
if x in long_dict:
#calculate the similarity by summing the products of the tf-idf_norm
similarity += short_dict[x] * long_dict[x]
Et si vous ne avez pas besoin des deux dictionnaires pour quoi que ce soit d'autre, vous pouvez créer seulement un et itérer sur la tuples B (clé, valeur) comme ils pop out de votre requête B Après la docb = cursor2.fetchall()
, remplacer tout le code ci-dessous par ceci:
similarity = 0
for b_token, b_value in docb:
if b_token in doca_dic:
similarity += doca_dic[b_token] * b_value
alternative au code ci-dessus: Cela fait plus de travail mais il fait plus de itérer en C au lieu de Python et peut être plus rapide.
similarity = sum(
doca_dic[k] * docb_dic[k]
for k in set(doca_dic) & set(docb_dic)
)
Version finale du code Python
# Doc A
cursor1.execute("SELECT token, tfidf_norm FROM index WHERE doc_id = %s", (docid[i][0]))
doca = cursor1.fetchall()
# Doc B
cursor2.execute("SELECT token, tfidf_norm FROM index WHERE doc_id = %s", (docid[j][0]))
docb = cursor2.fetchall()
if len(doca) < len(docb):
short_doc, long_doc = doca, docb
else:
short_doc, long_doc = docb, doca
long_dict = dict(long_doc) # yes, it should be that simple
similarity = 0
for key, value in short_doc:
if key in long_dict:
similarity += long_dict[key] * value
Un autre point pratique: vous avez pas dit quelle partie il est lent ... travailler sur les dicts ou faire Selects? Mettez quelques appels de time.time()
dans votre script. Envisagez de pousser TOUT le travail sur la base de données. L'exemple suivant utilise une requête SQLite câblée mais le principe est le même.
C:\junk\so>sqlite3
SQLite version 3.6.14
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> create table atable(docid text, token text, score float,
primary key (docid, token));
sqlite> insert into atable values('a', 'apple', 12.2);
sqlite> insert into atable values('a', 'word', 29.67);
sqlite> insert into atable values('a', 'zulu', 78.56);
sqlite> insert into atable values('b', 'apple', 11.0);
sqlite> insert into atable values('b', 'word', 33.21);
sqlite> insert into atable values('b', 'zealot', 11.56);
sqlite> select sum(A.score * B.score) from atable A, atable B
where A.token = B.token and A.docid = 'a' and B.docid = 'b';
1119.5407
sqlite>
Et il est bon de vérifier que la table de base de données est correctement indexé (par exemple un sur token
par lui-même) ... ne pas avoir un indice utile est une bonne façon de faire une requête SQL exécuter très lentement. Explication: Avoir un index sur token
peut rendre vos requêtes existantes ou la requête "faire tout le travail dans la base de données" ou les deux s'exécuter plus rapidement, selon les caprices de l'optimiseur de requête dans votre logiciel DB et la phase de la lune. Si vous n'avez pas d'index utilisable, la base de données lira TOUTES les lignes de votre table - ce qui n'est pas bien.
Création d'un index: create index atable_token_idx on atable(token);
suppression d'un index: drop index atable_token_idx;
(mais ne consulter la documentation pour votre DB)
+1 John c'était une grosse erreur! :) –
"Et si vous n'avez pas besoin des deux dictionnaires pour quelque chose d'autre, vous pouvez créer seulement le un et itérer sur les tuples B (clé, valeur) quand ils sortent de votre requête B." Je ne sais pas. Comment puis-je les parcourir au fur et à mesure qu'ils sortent de ma requête? (désolé si c'est évident) Merci beaucoup pour votre aide. Je dois dire que ce site et les gens sont géniaux. – seanieb
@seanieb: voir ma réponse mise à jour. –