A propos de votre table
Tout d'abord, je pense que vous devriez changer votre type de données en tableau simple.
CREATE TABLE public.vector (
id serial NOT NULL,
vctor double precision [3] --for three dimensional vectors; of course you can change the dimension or leave it unbounded if you need it.
);
INSERT INTO public.vector (vctor) VALUES (ARRAY[2,3,4]);
INSERT INTO public.vector (vctor) VALUES (ARRAY[3,4,5]);
Alors
SELECT * FROM public.vector;
Les données suivantes seront obtenues
id | vctor
------|---------
1 | {2,3,4}
2 | {3,4,5}
Ce n'est peut-être pas la réponse que vous attendiez, mais considérez ceci
Comme vous le savez peut-être déjà, calculer le cosinus entre les vecteurs implique de calculer les magnitudes. Je ne pense pas que le problème soit l'algorithme mais l'implémentation ; il nécessite de calculer des carrés et des racines carrées, ce qui est coûteux pour un SGBDR.
En ce qui concerne l'efficacité, le processus du serveur ne prend pas en charge l'appel des fonctions mathématiques. Dans PostgreSQL, les fonctions mathématiques ( regardez ici ) s'exécutent à partir de la bibliothèque C et sont donc assez efficaces. Cependant, au final, l'hôte doit affecter certaines ressources pour effectuer ces calculs.
Je réfléchirais en effet soigneusement avant de mettre en œuvre ces opérations plutôt coûteuses à l'intérieur du serveur. Mais il n'y a pas de bonne réponse ; cela dépend de l'utilisation que vous faites de la base de données. Par exemple, s'il s'agit d'une base de données de production avec des milliers d'utilisateurs simultanés, je déplacerais ce type de calcul ailleurs (une couche intermédiaire ou une application utilisateur). Mais s'il y a peu d'utilisateurs et que votre base de données est destinée à une petite opération de recherche, il est possible de l'implémenter en tant que procédure stockée ou processus s'exécutant dans votre serveur, mais gardez à l'esprit que cela affectera l'évolutivité ou la portabilité. Bien sûr, il y a d'autres considérations à prendre en compte, comme le nombre de lignes à traiter, ou si vous avez l'intention ou non de déclencher des triggers, etc.
Envisager d'autres solutions
Créer une application client
Vous pouvez réaliser un programme rapide et correct en VB ou dans le langage de votre choix. Laissez l'application client effectuer les calculs lourds et utilisez la base de données pour ce qu'elle fait de mieux, à savoir stocker et récupérer des données.
Stocker les données différemment
Pour cet exemple particulier, vous pourriez stocker les vecteurs unitaires plus la magnitude. De cette façon, trouver le cosinus entre deux vecteurs quelconques se réduit simplement au produit scalaire des vecteurs unitaires (uniquement multiplication et division, sans carré ni racine carrée).
CREATE TABLE public.vector (
id serial NOT NULL,
uvctor double precision [3], --for three dimensional vectors; of course you can change the dimension or make it decimal if you need it
magnitude double precision
);
INSERT INTO public.vector (vctor) VALUES (ARRAY[0.3714, 0.5571, 0.7428], 5.385); -- {Ux, Uy, Uz}, ||V|| where V = [2, 3, 4];
INSERT INTO public.vector (vctor) VALUES (ARRAY[0.4243, 0.5657, 0.7071], 7.071); -- {Ux, Uy, Uz}, ||V|| where V = [3, 4, 5];
SELECT a.vctor as a, b.vctor as b, 1-(a.uvctor[1] * b.uvctor[1] + a.uvctor[2] * b.uvctor[2] + a.uvctor[3] * b.uvctor[3]) as cosine_distance FROM public.vector a
JOIN public.vector b ON a.id != b.id;
Résultant en
a | b | cosine_distance
-----------------------------|------------------------------|------------------
{0.3714,0.5571,0.7428,5.385} | {0.4243,0.5657,0.7071,7.071} | 0.00202963
{0.4243,0.5657,0.7071,7.071} | {0.3714,0.5571,0.7428,5.385} | 0.00202963
Même si vous devez calculer la magnitude du vecteur à l'intérieur du serveur, vous le ferez une fois par vecteur et non pas chaque fois que vous aurez besoin d'obtenir la distance entre deux d'entre eux. Cela devient plus important au fur et à mesure que le nombre de lignes augmente. Pour 1000 vecteurs par exemple, vous devrez calculer la magnitude 999000 fois si vous voulez obtenir la différence en cosinus entre deux vecteurs quelconques en utilisant les composants originaux du vecteur.
Toute combinaison des éléments ci-dessus
Conclusion
Lorsque nous recherchons l'efficacité, la plupart du temps, il n'y a pas de réponse canonique. Il s'agit plutôt de compromis que nous devons considérer et évaluer. Cela dépend toujours de l'objectif final que nous devons atteindre. Les bases de données sont excellentes pour stocker et récupérer des données ; elles peuvent certainement faire d'autres choses, mais cela a un coût supplémentaire. Si nous pouvons vivre avec ce surcoût, c'est parfait ; sinon, nous devons envisager d'autres solutions.