Question

Il y a une table:

doc_id(integer)-value(integer)

approximatif 100.000 doc_id et 27.000.000 lignes.

requête majoritaire sur ce tableau - recherche de documents similaires à présent document:

select 10 documents with maximum of 
     (count common to current document value)/(count ov values in document).

Aujourd'hui, nous utilisons PostgreSQL. Table poids (avec index) ~ 1,5 Go. temps de recherche moyen ~ 0.5s - il est à hauteur. Et mon avis cette fois-ci grandira exponentielle avec la croissance de la base de données.

Dois-je transférer tout cela à la base NoSQL, si oui, quoi?

QUERY:

EXPLAIN ANALYZE
SELECT D.doc_id as doc_id,
  (count(D.doc_crc32) *1.0 / testing.get_count_by_doc_id(D.doc_id))::real as avg_doc 
FROM testing.text_attachment D
WHERE D.doc_id !=29758 -- 29758 - is random id
  AND D.doc_crc32 IN (select testing.get_crc32_rows_by_doc_id(29758)) -- get_crc32... is IMMUTABLE
GROUP BY D.doc_id
ORDER BY avg_doc DESC
LIMIT 10

Limit  (cost=95.23..95.26 rows=10 width=8) (actual time=1849.601..1849.641 rows=10 loops=1)
   ->  Sort  (cost=95.23..95.28 rows=20 width=8) (actual time=1849.597..1849.609 rows=10 loops=1)
         Sort Key: (((((count(d.doc_crc32))::numeric * 1.0) / (testing.get_count_by_doc_id(d.doc_id))::numeric))::real)
         Sort Method:  top-N heapsort  Memory: 25kB
         ->  HashAggregate  (cost=89.30..94.80 rows=20 width=8) (actual time=1211.835..1847.578 rows=876 loops=1)
               ->  Nested Loop  (cost=0.27..89.20 rows=20 width=8) (actual time=7.826..928.234 rows=167771 loops=1)
                     ->  HashAggregate  (cost=0.27..0.28 rows=1 width=4) (actual time=7.789..11.141 rows=1863 loops=1)
                           ->  Result  (cost=0.00..0.26 rows=1 width=0) (actual time=0.130..4.502 rows=1869 loops=1)
                     ->  Index Scan using crc32_idx on text_attachment d  (cost=0.00..88.67 rows=20 width=8) (actual time=0.022..0.236 rows=90 loops=1863)
                           Index Cond: (d.doc_crc32 = (testing.get_crc32_rows_by_doc_id(29758)))
                           Filter: (d.doc_id <> 29758)
 Total runtime: 1849.753 ms
(12 rows)
Était-ce utile?

La solution

1,5 Gigaoctets est rien. Servir de bélier. Construire une structure de données qui vous aide à la recherche.

Autres conseils

Je ne pense pas que votre principal problème est le genre de base de données ici que vous utilisez, mais le fait que vous ne possèdent en effet un « indice » pour ce que vous cherchez. Similitude entre documents

Ma proposition est de déterminer une fois qui sont les 10 documents semblables à chacun des 100.000 doc_ids et cache le résultat dans une nouvelle table comme ceci:

doc_id(integer)-similar_doc(integer)-score(integer)

où vous allez insérer 10 lignes par document chacun d'entre eux représentant les 10 meilleurs matchs pour elle. Vous aurez des lignes que vous 400.000 pouvez accéder directement par index qui devrait prendre le temps d'arrêt de recherche à quelque chose comme O (log n) (en fonction de la mise en œuvre de l'indice).

Ensuite, sur chaque insertion ou le retrait d'un document (ou une de ses valeurs) vous itérer les documents et mettre à jour la nouvelle table en conséquence.

par exemple. lors de l'insertion d'un nouveau document: pour chacun des documents déjà dans le tableau

  1. vous son score de calculer et correspondance
  2. si le score est plus élevé que le score le plus bas des documents similaires mises en cache dans la nouvelle table que vous échangez dans le similar_doc et le score du document nouvellement inséré

Si vous obtenez que les mauvaises performances de PostgreSQL, un bon début serait de régler PostgreSQL, votre requête et peut-être votre modèle de données. Une requête qui devrait servir comme beaucoup plus vite sur une telle petite table.

Tout d'abord, est 0.5s un problème ou non? Et vous avez déjà optimiser vos requêtes, dataModel et les paramètres de configuration? Sinon, vous pouvez toujours obtenir de meilleures performances. La performance est un choix.

En plus de la vitesse, il y a aussi une nouvelle fonctionnalité, c'est ce que vous perdrez.

===

Qu'en est-il de pousser la fonction à un JOIN:

EXPLAIN ANALYZE
SELECT 
    D.doc_id as doc_id,
    (count(D.doc_crc32) *1.0 / testing.get_count_by_doc_id(D.doc_id))::real as avg_doc 
FROM 
    testing.text_attachment D
        JOIN (SELECT testing.get_crc32_rows_by_doc_id(29758) AS r) AS crc ON D.doc_crc32 = r
WHERE 
    D.doc_id <> 29758
GROUP BY D.doc_id
ORDER BY avg_doc DESC
LIMIT 10
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top