Suite

Utilisation d'un polygone de délimitation au lieu d'un cadre de délimitation


J'ai un grand nombre de coordonnées LAT/LON. Jusqu'à présent, lorsque je devais sélectionner ceux qui se trouvaient dans une certaine région, je créais simplement un cadre de délimitation en utilisant des valeurs MINx, MAXx, MINy, MAXy et j'essayais de le rapprocher le plus possible de la zone dans laquelle j'étais intéressé par.

J'aimerais être plus précis en utilisant plus de 4 points comme étendue de ma zone de recherche, dans ce cas précis, 14 points.

J'utiliserai probablement Python ou SQL pour cela, donc la syntaxe spécifique de n'importe quelle solution n'est pas si importante, je suis juste intéressé par la formule pour comprendre celle-ci.


Vous pouvez utiliser Shapely pour effectuer l'opération (par exemple, à l'intérieur). Vous pouvez charger les deux géométries via l'une des méthodes d'interopérabilité de Shapely.


PostGIS possède une collection d'opérateurs relationnels qui devraient faire ce que vous voulez.


Volume englobant

En infographie et en géométrie computationnelle, un volume englobant car un ensemble d'objets est un volume fermé qui contient complètement l'union des objets de l'ensemble. Les volumes englobants sont utilisés pour améliorer l'efficacité des opérations géométriques en utilisant des volumes simples pour contenir des objets plus complexes. Normalement, les volumes plus simples ont des moyens plus simples de tester le chevauchement.

Un volume englobant pour un ensemble d'objets est également un volume englobant pour l'objet unique constitué de leur union, et inversement. Il est donc possible de cantonner la description au cas d'un seul objet, supposé non vide et borné (fini).


Boîte englobante

Une boîte englobante (généralement abrégée en bbox) est une zone définie par deux longitudes et deux latitudes, où :

  • La latitude est un nombre décimal compris entre -90,0 et 90,0.
  • La longitude est un nombre décimal compris entre -180,0 et 180,0.

Ils suivent généralement le format standard de :

Par exemple, le Grand Londres est délimité par :

Le lien « exporter les données » sur le site Web principal vous permet de dessiner une boîte et les coordonnées des bords vous sont affichées.

Dans un WikiProject ayant une sous-page de paramètres, vous pouvez obtenir le cadre de délimitation en utilisant le modèle pBbox.


Comme lealand a soulevé "largeur" ​​et "hauteur" sont des termes quelque peu vagues.

Voici une approche simple pour trouver la largeur et la hauteur de l'AABB :

Un polygone n'a pas de hauteur en largeur, car c'est simplement une collection de sommets. En fait, ces propriétés n'ont de sens que dans la mesure où nous les utilisons couramment lorsque vous en avez quatre (comme dans un rectangle).

Vous devrez définir et écrire vos propres méthodes pour calculer ces propriétés. Par exemple, la largeur peut être définie comme la distance maximale entre deux sommets et la hauteur peut être la longueur entre le milieu de cette ligne et le troisième sommet.


Votre code ressemble remarquablement au code awt réel utilisé dans Polygon pour obtenir le boundingBox. , commencez par des valeurs min/max extrêmes, puis partez de là.

Je trouve souvent que le choix d'utiliser les fonctions min()/max() au lieu des conditions if est également le plus rapide, donc je suis d'accord avec votre code là-bas.

Ce qui m'inquiète un peu, c'est l'utilisation de:

C'est un appel intéressant, qui peut ou non faire beaucoup de travail. Considérez sa mise en œuvre :

Si les bornes ont été préalablement calculées, alors ce sera très rapide. Sinon, il devra faire beaucoup de travail et créer en plus un tas d'instances de Rectangle .

Essentiellement, si vous vérifiez souvent les limites et ne modifiez pas les polygones, alors votre vérification des limites est assez bien amortie. Sinon, vous faites beaucoup de travail inutile.

Afin d'améliorer le temps écoulé (temps d'exécution), les deux seules choses que je peux recommander sont :

Le parallélisme/primitif combiné serait facile à implémenter en utilisant les flux Java 8 et en abusant du fait que les données Polygon sont publiques.

Le code ci-dessus conviendra car il introduit facilement le parallélisme. Si vous vous contentez d'un seul thread, un primitif uniquement, je recommanderais quelque chose comme :

Ce qui précède sera plus rapide lorsque vous devrez de toute façon recalculer toutes les limites poly.

Malheureusement, tout dépend de votre cas d'utilisation et de votre capacité à multithread.

Si vous êtes contraint, alors vous pouvez aussi vous en tenir à ce que vous avez, c'est rapide, soigné et sinon très bien.


Syntaxe

Classe d'entités ponctuelles ou surfaciques pour laquelle l'analyse des points chauds sera effectuée.

Classe d'entités en sortie pour recevoir les résultats du score z, de la valeur p et de Gi_Bin.

Le champ numérique (nombre d'incidents, taux de criminalité, résultats aux tests, etc.) à évaluer.

La méthode d'agrégation à utiliser pour créer des entités pondérées pour l'analyse à partir de données ponctuelles d'incident.

  • COUNT_INCIDENTS_WITHIN_FISHNET_POLYGONS —Un maillage de polygone en résille recouvrira les données de point d'incident et le nombre d'incidents dans chaque cellule de polygone sera compté. Si aucun polygone englobant n'est fourni dans le paramètre Bounding_Polygons_Defining_Where_Incidents_Are_Possible, seules les cellules avec au moins un incident seront utilisées dans l'analyse, sinon toutes les cellules dans les polygones englobants seront analysées.
  • COUNT_INCIDENTS_WITHIN_AGGREGATION_POLYGONS : vous fournissez des polygones d'agrégation pour superposer les données de point d'incident dans le paramètre Polygons_For_Agregating_Incidents_Into_Counts. Les incidents à l'intérieur de chaque polygone sont comptés.
  • SNAP_NEARBY_INCIDENTS_TO_CREATE_WEIGHTED_POINTS —Les incidents à proximité seront agrégés pour créer un seul point pondéré. Le poids pour chaque point est le nombre d'incidents agrégés à cet endroit.

Une classe d'entités surfaciques définissant où l'incident Input_Features pourrait éventuellement se produire.

Les polygones à utiliser pour agréger les Input_Features incidentes afin d'obtenir un nombre d'incidents pour chaque entité surfacique.

Surface de densité en sortie des entités ponctuelles en entrée. Ce paramètre n'est activé que lorsque Input_Features sont des points et que vous disposez de l'extension ArcGIS Spatial Analyst . La surface de sortie créée sera découpée sur le masque d'analyse raster spécifié dans vos paramètres d'environnement. Si aucun masque raster n'est spécifié, la couche raster en sortie sera découpée en une enveloppe convexe des entités en entrée.


Paramètres

Classe d'entités ponctuelles ou surfaciques pour laquelle l'analyse d'agrégats et de valeurs aberrantes sera effectuée.

Classe d'entités en sortie pour recevoir les champs de résultat.

Le champ numérique (nombre d'incidents, taux de criminalité, résultats aux tests, etc.) à évaluer.

La méthode d'agrégation à utiliser pour créer des entités pondérées pour l'analyse à partir de données ponctuelles d'incident.

  • Compter les incidents dans la grille de résille : un maillage de polygone de résille recouvrira les données de point d'incident et le nombre d'incidents dans chaque cellule de polygone sera compté. Si aucun polygone de délimitation n'est fourni dans le paramètre Polygones de délimitation définissant où des incidents sont possibles, seules les cellules avec au moins un incident seront utilisées dans l'analyse, sinon toutes les cellules des polygones de délimitation seront analysées.
  • Compter les incidents dans la grille hexagonale : un maillage de polygone hexagonal recouvrira les données de point d'incident et le nombre d'incidents dans chaque cellule de polygone sera compté. Si aucun polygone de délimitation n'est fourni dans le paramètre Polygones de délimitation définissant où des incidents sont possibles, seules les cellules avec au moins un incident seront utilisées dans l'analyse, sinon toutes les cellules des polygones de délimitation seront analysées.
  • Compter les incidents dans les polygones d'agrégation : vous fournissez des polygones d'agrégation pour superposer les données de point d'incident dans le paramètre Polygones pour l'agrégation d'incidents en nombres. Les incidents à l'intérieur de chaque polygone sont comptés.
  • Capturez les incidents à proximité pour créer des points pondérés : les incidents à proximité seront agrégés pour créer un seul point pondéré. Le poids pour chaque point est le nombre d'incidents agrégés à cet endroit.

Une classe d'entités surfaciques définissant où les entités en entrée incidentes pourraient éventuellement se produire.

Les polygones à utiliser pour agréger les entités en entrée incidentes afin d'obtenir un nombre d'incidents pour chaque entité surfacique.

Cette analyse utilise des permutations pour créer une distribution de référence. Le choix du nombre de permutations est un équilibre entre précision et augmentation du temps de traitement. Choisissez votre préférence pour la vitesse par rapport à la précision. Des résultats plus robustes et précis prennent plus de temps à calculer.

  • Rapide (199 permutations) : avec 199 permutations, la pseudo-valeur de p la plus petite possible est de 0,005 et toutes les autres pseudo-valeurs de p seront des multiples pairs de cette valeur.
  • Équilibré (499 permutations) : avec 499 permutations, la pseudo-valeur p la plus petite possible est 0,002 et toutes les autres pseudo-valeurs p seront des multiples pairs de cette valeur.
  • Robuste (999 permutations) : avec 999 permutations, la pseudo-valeur p la plus petite possible est 0,001 et toutes les autres pseudo-valeurs p seront des multiples pairs de cette valeur.

La taille des cellules de grille utilisées pour agréger les entités en entrée . Lors de l'agrégation dans une grille hexagonale, cette distance est utilisée comme hauteur pour construire les polygones hexagonaux.

L'étendue spatiale du voisinage d'analyse. Cette valeur détermine quelles caractéristiques sont analysées ensemble afin d'évaluer le regroupement local.

Classe d'entités ponctuelles ou surfaciques pour laquelle l'analyse d'agrégats et de valeurs aberrantes sera effectuée.

Classe d'entités en sortie pour recevoir les champs de résultat.

Le champ numérique (nombre d'incidents, taux de criminalité, résultats aux tests, etc.) à évaluer.

La méthode d'agrégation à utiliser pour créer des entités pondérées pour l'analyse à partir de données ponctuelles d'incident.

  • COUNT_INCIDENTS_WITHIN_FISHNET_POLYGONS — Un maillage de polygone en résille recouvrira les données de point d'incident et le nombre d'incidents dans chaque cellule de polygone sera compté. Si aucun polygone englobant n'est fourni dans le paramètre Bounding_Polygons_Defining_Where_Incidents_Are_Possible, seules les cellules avec au moins un incident seront utilisées dans l'analyse, sinon toutes les cellules dans les polygones englobants seront analysées.
  • COUNT_INCIDENTS_WITHIN_HEXAGON_POLYGONS — Un maillage de polygone hexagonal superposera les données de point d'incident et le nombre d'incidents dans chaque cellule de polygone sera compté. Si aucun polygone englobant n'est fourni dans le paramètre Bounding_Polygons_Defining_Where_Incidents_Are_Possible, seules les cellules avec au moins un incident seront utilisées dans l'analyse, sinon toutes les cellules dans les polygones englobants seront analysées.
  • COUNT_INCIDENTS_WITHIN_AGGREGATION_POLYGONS — Vous fournissez des polygones d'agrégation pour superposer les données de point d'incident dans le paramètre Polygons_For_Agregating_Incidents_Into_Counts. Les incidents à l'intérieur de chaque polygone sont comptés.
  • SNAP_NEARBY_INCIDENTS_TO_CREATE_WEIGHTED_POINTS — Les incidents à proximité seront agrégés pour créer un seul point pondéré. Le poids pour chaque point est le nombre d'incidents agrégés à cet endroit.

Une classe d'entités surfaciques définissant où l'incident Input_Features pourrait éventuellement se produire.

Les polygones à utiliser pour agréger les Input_Features incidentes afin d'obtenir un nombre d'incidents pour chaque entité surfacique.

Cette analyse utilise des permutations pour créer une distribution de référence. Le choix du nombre de permutations est un équilibre entre précision et augmentation du temps de traitement. Choisissez votre préférence pour la vitesse par rapport à la précision. Des résultats plus robustes et précis prennent plus de temps à calculer.

  • QUICK_199 — Avec 199 permutations, la pseudo-valeur p la plus petite possible est 0,005 et toutes les autres pseudo-valeurs p seront des multiples pairs de cette valeur.
  • BALANCED_499 — Avec 499 permutations, la pseudo-valeur de p la plus petite possible est 0,002 et toutes les autres pseudo-valeurs de p seront des multiples pairs de cette valeur.
  • ROBUST_999 — Avec 999 permutations, la pseudo-valeur p la plus petite possible est 0,001 et toutes les autres pseudo-valeurs p seront des multiples pairs de cette valeur.

La taille des cellules de grille utilisées pour agréger les Input_Features . Lors de l'agrégation dans une grille hexagonale, cette distance est utilisée comme hauteur pour construire les polygones hexagonaux.

L'étendue spatiale du voisinage d'analyse. Cette valeur détermine quelles caractéristiques sont analysées ensemble afin d'évaluer le regroupement local.

Exemple de code

Le script de fenêtre Python suivant montre comment utiliser l'outil OptimizedOutlierAnalysis.

Le script Python autonome suivant montre comment utiliser l'outil OptimizedOutlierAnalysis.


Syntaxe

Les entités en entrée qui peuvent être ponctuelles, multipoints, linéaires, polygonales ou multipatch.

La classe d'entités surfaciques en sortie.

Spécifie le type de géométrie de délimitation minimale que les polygones en sortie représenteront.

  • RECTANGLE_BY_AREA —Rectangle de la plus petite zone entourant une entité en entrée. C'est la valeur par défaut.
  • RECTANGLE_BY_WIDTH —Rectangle de la plus petite largeur entourant une entité en entrée.
  • CONVEX_HULL —Le plus petit polygone convexe englobant une entité en entrée.
  • CIRCLE —Le plus petit cercle entourant une entité en entrée.
  • ENVELOPE —Enveloppe d'une entité en entrée.
Licence:

Les options CONVEX_HULL , CIRCLE et ENVELOPE ne sont disponibles qu'avec une licence ArcGIS for Desktop Advanced.

Spécifie comment les entités en entrée seront regroupées. Chaque groupe sera entouré d'un polygone en sortie.

  • NONE : les entités en entrée ne seront pas regroupées. C'est la valeur par défaut. Cette option n'est pas disponible pour la saisie de points.
  • ALL —Toutes les entités en entrée seront traitées comme un seul groupe.
  • LIST —Les entités en entrée seront regroupées en fonction de leurs valeurs communes dans le ou les champs spécifiés dans le paramètre de champ de groupe.

Le ou les champs des entités en entrée qui seront utilisés pour regrouper les entités, lorsque LIST est spécifié en tant que group_option . Au moins un champ de groupe est requis pour l'option LISTE. Toutes les entités qui ont la même valeur dans le ou les champs spécifiés seront traitées comme un groupe.

Indique s'il faut ajouter les attributs géométriques dans la classe d'entités en sortie ou les omettre dans la classe d'entités en sortie.

  • NO_MBG_FIELDS —Omet tous les attributs en entrée dans la classe d'entités en sortie. C'est la valeur par défaut.
  • MBG_FIELDS —Ajoute les attributs géométriques dans la classe d'entités en sortie.

Le calcul de la boîte englobante d'une sphère est assez trivial étant donné la simplicité de la géométrie de la sphère.

Supposons que nous ayons le rayon de la sphère défini comme une valeur scalaire (float ou entier) $r$ , et le centre de la sphère défini comme un vecteur $overrightarrow c$ comme ceci :

$ overrightarrow c = eginx y zfin $

Nous pouvons calculer les vecteurs de coordonnées externes $overrightarrow$ et $overrightarrow$ en procédant comme suit :

$ début overrightarrow &= egin c_x - r c_y - r c_z - r end overrightarrow &= egin c_x + r c_y + r c_z + r end finir $

Si nous préférons, une autre façon de calculer cette même chose est de définir un vecteur $overrightarrow <>>>$ pour avoir fait cet ajout, qui représente simplement le décalage du centre vers un coin de la boîte englobante :

$ exte overrightarrow c = eginx y zfin exte overrightarrow <>>> = commencer r r r fin, commencer overrightarrow &= overrightarrow c - overrightarrow <>>> overrightarrow &= overrightarrow c + overrightarrow <>>> fin $


Rendre les jointures géospatiales interactives à grande échelle

Les jointures SQL sont l'opération de base de données par excellence. Une jointure permet à l'utilisateur de découper et de découper plusieurs ensembles de données disparates, par exemple, en combinant des données de transaction avec des références de produits ou des informations client avec l'historique des achats. Des résultats similaires pourraient être créés sans jointure, mais nécessitent de larges tables plates et éventuellement un pré et post-traitement lourd. Correctement exécutées, les jointures offrent de la flexibilité, augmentent les performances et permettent une large gamme d'exploration de données.

Cependant, les jointures sont, par définition, coûteuses. Une jointure combine les colonnes d'une ou plusieurs tables dans une nouvelle table en utilisant un ou plusieurs prédicats pour faire correspondre les lignes. Il est instructif pour les programmeurs de penser à une opération JOIN sémantiquement équivalente à une pour boucle. Étant donné la requête suivante, qui combine les enregistrements de la table t1 et tableau t2 en utilisant la colonne de prédicat une dans le tableau t1 égal à la colonne b dans le tableau t2, on peut écrire un pseudo-code pour boucle comme suit:

Une telle opération a une complexité N * M, où N est le nombre d'enregistrements dans t1 et M est le nombre d'enregistrements dans t2. Pour les petites tables, c'est trivial (en particulier sur les GPU). Néanmoins, pour les grandes tables ou les prédicats de jointure complexes, nous dépassons rapidement la capacité de calcul des systèmes à serveur unique les plus puissants. L'optimisation des jointures est un domaine bien étudié de la recherche sur les bases de données, et de nombreuses approches bien connues atténuent le problème du « N au carré » détaillé ci-dessus. Une approche courante consiste à tirer parti d'une structure de données de table de hachage pour réduire le nombre de tests de correspondance requis entre les deux tables. Cette méthode crée une table de hachage sur l'une des tables, et la boucle est complétée par une recherche dans la table de hachage pour obtenir l'ensemble potentiel de lignes correspondantes :

Bien que la structure de la boucle reste similaire à notre premier exemple, la table de hachage peut réduire considérablement le nombre de recherches dans la deuxième boucle. Dans le meilleur des cas, la table de hachage peut fournir à la fois une recherche en temps constant et des garanties d'égalité strictes, réduisant la boucle à :

OmniSciDB prend en charge les jointures de hachage avec la construction à la volée de tables de hachage sur le CPU et le GPU. Plusieurs fonctions de hachage sont prises en charge en fonction de la complexité du prédicat d'égalité et/ou de la taille de la jointure. Aujourd'hui, nous allons envisager d'accélérer les requêtes de jointure géospatiale à l'aide de jointures de hachage.

Nous définissons une requête de jointure géospatiale comme une requête qui utilise un opérateur géospatial comme prédicat de jointure. Un utilisateur peut avoir une table de tweets géocodés avec la longitude et la latitude et vouloir déterminer dans quel code postal le tweet appartient - éventuellement en coloriant les tweets par code postal sur une carte rendue dans Immerse. Une telle requête peut ressembler à ce qui suit :

(notez que la jointure gauche préserve les tweets sans correspondance dans les ensembles de données de codes postaux, ce qui signifie qu'un tweet sera inclus avec une couleur « NULL » s'il n'a pas de code postal correspondant, plutôt qu'exclu)

Pour déterminer si un tweet se trouve à l'intérieur d'un code postal donné, nous devons vérifier de manière exhaustive le point d'emplacement du tweet par rapport à chaque polygone de code postal. La plupart des algorithmes nécessitent une vérification de chaque sommet du polygone du code postal (il existe quelques méthodes pour ce faire, nous utilisons la méthode d'enroulement) par rapport à chaque point. En supposant que nous ayons 1 million de tweets et 33 144 codes postaux, comparer chaque point à chaque polygone donnerait 33 milliards de comparaisons. Étant donné que le code postal médian a 166 sommets, nous ajoutons plus de zéros pour 5 501 904 000 000 de comparaisons totales (5,5 billions d'opérations). Cela ne tient pas compte des opérations nécessaires pour charger les données, vérifier les conditions aux limites, etc., nous pouvons donc le considérer comme une limite inférieure. Les derniers GPU Ampere ont près de dix téraflops, ce qui exécute l'opération ci-dessus en environ 500 ms, mais si nous augmentons notre table de tweets à 100M, nous voyons le temps de calcul augmenter à 6 minutes. La plupart des clients OmniSci utilisent des données comprises entre 500 millions et quelques milliards, et la plupart des requêtes dans OmniSci s'exécutent en quelques millisecondes. Nous devons donc utiliser une certaine optimisation pour rendre les géojointures interactives.

Bien que cela ne soit pas évident, nous pouvons appliquer la même technique de table de hachage décrite ci-dessus à la table des codes postaux. Nous avons d'abord besoin de deux conditions, nous avons besoin d'une fonction de hachage appropriée pour construire notre table de hachage. De plus, nous avons besoin d'une expression à hacher qui a la propriété suivante : ST_Contains est vrai si l'expression de jointure de hachage est également vraie. Nous introduisons un nouvel opérateur appelé Overlaps, qui satisfait cette propriété.

Nous définissons les chevauchements(b, un) ou alors une chevauchements b être vrai si la boîte englobante de l'objet une chevauche le cadre de délimitation de l'objet b. Notez que cet opérateur peut être mieux nommé Environ Chevauchements nous nous en tiendrons aux chevauchements pour le reste de cet article par souci de concision. Pour un point, nous considérons que la boîte englobante s'effondre jusqu'au point. Donc si une est un point et b est un autre objet géospatial, Overlaps renvoie true si le point une est à l'intérieur de la boîte englobante entourant l'objet b. Nous allons maintenant prouver que ST_Contains est vrai si et seulement si Overlaps est vrai. Supposons que nous ayons un point une et un objet géospatial b et un cadre englobant b_boîte. Supposons que ST_Contient(b,une) est vrai (c'est-à-dire l'objet géospatial b contient le point une) et supposer des chevauchements(b,une) est faux (c'est-à-dire une ne se chevauche pas b). La boîte englobante b_boîte contient b par définition. Donc si b contient une, ensuite une doit être à l'intérieur de la boîte englobante pour b. Donc une chevauchements b. Cependant, nous avons supposé des chevauchements(b,une) était faux, nous avons donc une contradiction et, si ST_Contains(b,une) est vrai, alors Overlaps(b,une) doit également être vrai.

Nous pouvons utiliser cette propriété pour remplacer l'expression ST_Contains(b,une) dans la requête avec le prédicat binaire Overlaps(b,une) ET ST_Contient(b,une). Nous allons ensuite construire une table de hachage sur l'expression Overlaps(b,une) et utilisez la table de hachage pour réduire le nombre de comparaisons dans la jointure. Pour ce faire, nous avons besoin d'une fonction de hachage. Considérez les cadres de délimitation des objets géospatiaux b. Si nous prenons l'union de toutes les boîtes englobantes, en faisons un rectangle, puis subdivisons cette région en compartiments individuels, chacun de la même taille, nous pouvons créer une fonction qui mappe spatialement n'importe quel point une dans un bac. Une telle fonction attribue un identifiant entier à chaque casier, calculé en divisant les coordonnées du point par la dimension du casier correspondant et en prenant la parole. Les courbes de remplissage d'espace sont une autre option. Nous avons opté pour la fonction de hachage simple car nos données d'entrée ne sont ni triées ni ordonnées, et les requêtes ciblent généralement un seul compartiment, et non une plage de compartiments. Les propriétés de localité de mémoire des courbes de remplissage d'espace sont un domaine d'exploration future. Pour construire une table de hachage pour cette fonction, nous prenons le cadre de délimitation de chaque polygone, déterminons le ou les bacs que le cadre de délimitation chevauche et écrivons un identifiant pour le polygone dans chaque bac.

En mettant tout cela ensemble, nous combinons la nouvelle expression Overlaps(b, un) ET ST_Contient(b, un) avec la table de hachage sur Overlaps(b, un). Pour un point donné une, nous vérifions d'abord la table de hachage pour voir à quelle case appartient le point en appliquant la fonction de hachage au point. Nous lisons la liste des identifiants de polygones dans le bac. Cette opération calcule les chevauchements pour le point une et tous les polygones b (notez que la condition est un peu plus faible, en ce sens qu'un point pourrait être dans le même bac qu'un polygone mais les deux ne pourraient pas se chevaucher, mais c'est suffisant pour nos besoins car tout polygone qui ne se trouve pas dans le bac ne peut pas contenir le point - - voir figure 1). Ce processus limite le nombre total de comparaisons pour ST_Contains aux seuls polygones qui force contenir le point donné. Si les bacs sont peu occupés, nous pouvons réduire considérablement le nombre de comparaisons nécessaires pour chaque point. Le pseudocode suivant illustre ce processus :

Nous avons commencé avec une expression, ST_Contains(b, un), et réécrit l'expression en une expression équivalente, Overlaps(b, un) ET ST_Contient(b, un). Nous pouvons ensuite utiliser le framework de jointure de hachage avec une fonction de hachage et une table de hachage appropriées pour restreindre l'espace de recherche de l'expression et améliorer les performances. Alors, comment choisissons-nous les tailles de bac appropriées lors de la construction de la table de hachage ?

Le dimensionnement de la table de hachage est un compromis entre la taille de la table de hachage et le nombre d'enregistrements dans chaque bac. Moins il y a d'enregistrements dans chaque casier, moins nous avons de travail à faire par casier, cela signifie moins d'opérations ST_Contains coûteuses dans notre exemple ci-dessus. Cependant, à mesure que les bacs deviennent plus petits, plus de bacs doivent couvrir la même zone, ce qui augmente le temps de construction de la table de hachage et sa taille. Notre algorithme (voir figure 2) recherche une table de hachage avec une faible occupation des bacs, plafonnée à une taille maximale. Nous paramétrons la recherche sur le "bin seuil" la taille minimale du casier que nous autoriserons dans la table de hachage. Le tuner initialise la taille du bac en itérant sur tous les cadres de délimitation que nous voulons ajouter à notre table de hachage et détermine la taille du cadre de délimitation dans chaque dimension si cette taille de cadre de délimitation est inférieure au seuil de bac actuel mais supérieure à la valeur actuelle. la taille de bac choisie, nous la prenons comme nouvelle taille de bac. En abaissant le seuil de taille de bac, nous pouvons rechercher systématiquement à la fois la taille de la table de hachage et l'occupation du bac.

Nous allons parcourir en détail une étape du processus de réglage. Chaque étape calcule un ensemble de tailles de bacs unidimensionnels (le framework ne prend actuellement en charge que les bacs bidimensionnels mais est conçu pour prendre en charge une dimensionnalité arbitraire). Nous pouvons calculer la taille totale de la table de hachage et une métrique pour l'occupation moyenne des bacs à partir des tailles de bacs calculées. Nous utilisons la taille et l'occupation calculées pour décider s'il faut continuer le réglage. Tout d'abord, nous regardons si la table de hachage est trop grande. Si la table de hachage est devenue trop grande, nous utilisons les valeurs de seuil/tailles de bac précédemment déterminées. Cependant, si aucune valeur précédente n'existe, nous avons probablement dépassé la taille du bac et devons choisir un seuil plus important. Dans ce cas, l'algorithme s'inverse et sélectionne des bacs plus grands jusqu'à ce que nous ayons une table de hachage sous le seuil de taille. Les deux cas restants sont simples. Les clés par casier sont une mesure de l'occupation du casier, c'est-à-dire le nombre de cadres de délimitation chevauchant un casier donné (au total). Si les clés par casier augmentent, ou si nous avons atteint le seuil de clés par casier, nous terminons l'algorithme, en supposant que les coûts de taille d'une table de hachage plus grande l'emporteront sur tout gain d'occupation supplémentaire, et utilisons les valeurs de l'itération précédente.

Nous avons mené plusieurs expériences pour démontrer le processus de recherche de l'algorithme et le compromis entre l'occupation des bacs et la taille de la table de hachage. Les expériences ci-dessous utilisent un tableau de gauche avec des enregistrements géolocalisés de l'API publique de Twitter (le tableau "tweets"). Nous avons utilisé un AMD Threadripper 2950X avec deux GPU NVIDIA RTX 2080. Les tweets ont été chargés avec la taille de fragment standard (32 millions de lignes par fragment), réparties uniformément sur les deux GPU. Aucune optimisation supplémentaire n'a été appliquée. Nous avons utilisé trois tables de polygones comtés aux États-Unis (3 233 lignes avec 7 944 863 sommets totaux sur tous les polygones), des codes postaux aux États-Unis (33 144 lignes avec 52 210 207 sommets totaux) et des îlots de recensement aux États-Unis (220 740 lignes avec 67 581 813 sommets totaux) . La requête était une jointure à gauche entre la table des tweets et la table de polygones pertinente, la première exécution étant exclue pour éliminer la récupération initiale des données sur le disque. Nous avons utilisé un seul agrégat de comptage sans filtre dans la projection. Les données de chaque expérience sont dans les figures ci-dessous.

Toutes les expériences consistaient à définir une clé cible par paramètre bin et à déterminer la taille de la table de hachage résultante, le temps de construction et le temps d'exécution de la requête à l'aide de la table de hachage. À l'aide de ces chiffres, nous pouvons comprendre comment l'algorithme se comporte dans divers paramètres et ce que le compromis entre la taille de la table de hachage et l'occupation des emplacements signifie pour le temps de construction de la table de hachage et l'exécution des requêtes.

En général, les résultats montrent qu'à mesure que la table de hachage augmente, le temps de construction devient beaucoup plus coûteux et le temps d'exécution peut diminuer modérément, rester le même ou même augmenter. La figure des comtés américains dans les tweets affiche le temps sur l'axe des y, nous voyons que le temps de construction oscille énormément à des clés relativement basses par bac, à gauche de la ligne pointillée rouge. Nous voyons également des oscillations correspondantes dans la taille de la table de hachage. La figure 4 (ci-dessous) a tracé les seuils de bac choisis par rapport aux mêmes clés cibles par bac que dans la figure 3(b). Comme on peut s'y attendre, la plus grande table de hachage correspond à la plus petite taille de bac. Cependant, l'occupation et la taille de la table de hachage ne semblent pas être corrélées à ces petites tailles de bac.

Pour comprendre cette corrélation (ou l'absence de corrélation), nous revenons à l'algorithme de réglage pour prendre des décisions de réglage, nous devons sélectionner de nouvelles tailles de bac pour chaque étape. La réduction de la taille de bac précédente d'un pas fixe et la recherche de la plus grande dimension de cadre de délimitation sous le nouveau seuil détermine la nouvelle taille de bac par dimension. De cette façon, l'algorithme se déplace à travers les boîtes englobantes de différentes tailles, garantissant qu'au moins une boîte englobante s'insère approximativement dans un bac. En pratique, cela évite les tailles de compartiment mises à l'échelle par une taille fixe qui ne correspond pas à la géométrie sous-jacente (principalement puisque les unités de la géométrie sous-jacente peuvent varier selon le système de coordonnées). En combinant le sélecteur de taille de bac avec la taille de la table de hachage et les clés par métrique de bac, nous pouvons minimiser le temps d'exécution (en maximisant la taille de la table de hachage) en utilisant des clés par bac pour contrôler les temps de construction. En effet, la solution par défaut est soit à, soit relativement proche de l'optimum dans la figure 2.

Que se passe-t-il lorsque les bacs deviennent plus petits ? Une légère variation de la taille du bac à petite échelle entraîne une différence considérable dans la taille de la table de hachage. La petite taille de bac est généralement le résultat de nombreuses étapes car l'algorithme recherche dans les tailles de bac en fonction des données existantes et sélectionne des cadres de délimitation plus petits à chaque itération avec une taille de pas fixe. La métrique d'occupation des clés par bac change au fur et à mesure que nous travaillons sur des cadres de délimitation de tailles similaires. Soudain, nous passons à une boîte englobante beaucoup plus petite, ce qui fait augmenter considérablement la taille de la table de hachage et modifier l'occupation, ce qui met fin à l'algorithme à l'itération précédente (voir la figure 4b). Essentiellement, la métrique d'occupation des cases nous empêche de « passer à travers » les cadres de délimitation à un qui est beaucoup plus petit que la taille de cadre de délimitation « moyenne » dans l'ensemble de données.

En résumé, nos expériences montrent que la métrique d'occupation aide l'algorithme de réglage à éviter des changements dramatiques dans la taille de la table de hachage dus au " glissement vers le bas " vers le groupe suivant de cadres de délimitation, qui peut être beaucoup plus petit que notre groupe d'expérimentation. En combinant un seuil d'occupation minimum déterminé expérimentalement avec une tendance d'occupation, nous pouvons abandonner le réglage juste au bord d'une table de hachage raisonnablement grande (donnant une faible occupation des bacs et de bonnes performances) sans tomber dans une région instable où la taille de la table de hachage peut augmenter par commandes de magnitude ou osciller de façon sauvage à travers des métriques d'occupation similaires. Bien que cet algorithme produise des résultats solides, des optimisations supplémentaires sont possibles. Nous voulons résoudre le problème d'optimisation pour maximiser la taille de la table de hachage pour un seuil d'occupation donné et choisir un seuil d'occupation qui maximise le temps d'exécution de la requête sans créer un temps de construction déraisonnable. Considérez ceci comme notre première tentative d'approximation d'une solution.

Même si nous étudions des optimisations supplémentaires pour augmenter le parallélisme et les performances de notre approche de jointure par chevauchement, elle s'est déjà avérée extrêmement bénéfique pour amener les grandes géo-jointures à des niveaux de performance interactifs ou quasi interactifs. Sur une machine, avec 2 GPU Nvidia RTX 3090, les chevauchements se joignent à des performances accrues par rapport à une jointure en boucle entre 200 et 1 200X sur divers exemples, augmentant au maximum une jointure de tweets américains aux groupes de blocs de recensement américains à partir de 11,3 000 recherches par seconde avec boucle joindre à 22,38 millions de recherches par seconde avec des chevauchements. Enfin, nous pensons que des accélérations supplémentaires sont possibles. Par exemple, des expériences utilisant des courbes de remplissage d'espace pour ordonner et hacher les données suggèrent le potentiel de gagner 3 à 4 fois plus de performances en augmentant la localité spatiale et en réduisant la divergence d'exécution pendant la phase de sonde de la jointure par hachage, alors restez à l'écoute pour en savoir plus ce front.

Les jointures de points dans des polygones ne sont qu'un exemple d'application des techniques décrites ci-dessus. L'opérateur générique OVERLAPS s'applique à diverses requêtes, y compris des requêtes spatiales et temporelles (ou des combinaisons des deux). In general, two broad applications emerge queries requiring an algorithm to construct the hash table and queries that dictate the construction of the hash table based on the predicate defining the OVERLAPS relationship in the query. We have implemented distance joins between geospatial points as an example of the latter type if a user requests all points within N units of each other, we can construct the hash table such that a simple search of neighboring bins is always guaranteed to return the points which might be within N units of each other. While we are in the early stages of productionizing these techniques, the point in polygon join is available in OmniSci as of version 5.6 across all product modalities, including desktop, OmniSci Free, and the Enterprise Edition.

Alex Baden is the Technical Director leading the Query Engine team at OmniSci. Prior to OmniSci, he was a graduate student at Johns Hopkins University, studying computer science and developing terabyte scale databases and visualization tools, optimized for range queries across three dimensional image datasets. He has contributed code to various open source projects across the big data landscape and has worked with organizations such as the Allen Institute for Brain Science to develop tools for the analysis of large and complex datasets. He holds a MSE in Computer Science from Johns Hopkins University and a BS in Mathematics from the University of Maryland.