Comment utiliser la recherche de proximité Redis et geo pour trouver deux utilisateurs au même endroit?

je veux mettre en place un service qui, compte tenu des coordonnées géographiques des utilisateurs, peut détecter si deux utilisateurs sont au même endroit en temps réel.

afin de le faire en temps réel et à l'échelle, il semble que je devrais utiliser un datastore distribué en mémoire comme Redis. J'ai fait des recherches en utilisant geohashing, mais le problème est que les points proches les uns des autres ne partagent pas toujours le même préfixe de hachage. Et la géohashing peut être exagérée puisque je suis intéressé à trouver si deux utilisateurs sont suffisamment proches l'un de l'autre.

la solution simple est bien sûr juste de tester si des paires de coordonnées géographiques tombent à une petite distance l'une de l'autre. Mais AFAIK, Redis et d'autres données en mémoire n'ont pas d'indexation géospatiale pour supporter ce genre de recherche.

Quelle est la meilleure façon de mettre en œuvre ceci?

21
demandé sur Simian 2013-10-01 07:47:33

7 réponses

cette fonctionnalité est transformée en Redis 3.2+ .

mais pour les versions plus anciennes le problème existe toujours. J'ai pris la réponse de Yin Qiwen et créé un module pour Node, et vous pouvez voir comment il utilise Redis en examinant le code. Ses instructions sont parfaites et j'ai pu les suivre pour de grands résultats. https://github.com/arjunmehta/node-georedis

le même algorithme est essentiellement ce qui est utilisé pour les commandes natives.

il est très rapide, et évite toute sorte d'intersections/opérations de type haversine. La chose la plus cool (je pense) à propos de la méthode de Yin Qiwen est que les parties les plus computationnellement intenses de l'algorithme peuvent être distribuées aux clients (au lieu de tout ce qui se passe dans la base de données ou sur le serveur).

ce n'est pas précis à 100% et utilise des distances prédéfinies, mais pour la plupart des applications, vous n'aurez pas besoin de précision exacte, j'imagine.

j'ai aussi paraphrasé l'article de Yin Qiwen au GIS stack exchange .

désolé pour le lien. : P

16
répondu Arjun Mehta 2017-04-13 12:33:44

Généralement, cela pourrait être fait par GeoHash et Redis ensemble trié. Il y a une conception que j'ai écrite avant de parler de la mise en œuvre d'un service d'index spatial sur redis.

https://github.com/yinqiwen/ardb/wiki/Spatial-Index

15
répondu yinqiwen 2018-09-04 07:02:58

Peut-être que vous pouvez essayer celui-ci:

Redis Géographie Édition

Vous avez vraiment envie de l'essayer, ça fonctionne super. :)

7
répondu mzalazar 2015-02-17 21:50:02

je réalise que cela ne répond pas à votre question... mais je ne pense pas que ce soit le bon outil.

PostgreSQL + PostGIS pouvez effectuer vraiment, vraiment bien. Vous pouvez configurer PostgreSQL pour exécuter à peu près autant de la base de données qu'elle peut s'insérer dans la mémoire.

PostGIS utilise (je pense) les index rtree, donc il est incroyablement rapide pour effectuer le genre de recherche que vous êtes intéressé.

utilisant un backend qui déclenche websocket demandes vous permettra d'exécuter assez bien en temps réel. Chaque fois que votre serveur reçoit les coordonnées GPS d'une personne, effectuez la recherche spatiale et avisez les clients concernés par le biais de websockets.

5
répondu jreid42 2013-12-06 02:09:31

L'édition de géographie Redis mentionnée par d'autres réponses dans ce fil a été intégrée dans Redis depuis la version 3.2 (voir aussi ce commentaire antérieur ).

vous pouvez trouver les nouvelles commandes ici (en beta pour le moment):

5
répondu nha 2015-08-22 10:32:58

base de données Tarantool conserve les données en mémoire, les pousse sur le disque comme les journaux de transaction, a le type de rtree index spatial (non seulement bidimensionnel) et un certain nombre de belles opérations sur un tel index (confinement, Chevauchement, distance).

Je l'utilise dans un projet commercial pour stocker et interroger des documents qui décrivent des objets dans L'espace 3D.

http://tarantool.org/doc/book/box/box_index.html

https://github.com/tarantool/tarantool/wiki/R-tree-index-quick-start-and-usage

client Standard et exemples sont dans Lua, mais il ya quelques autres clients développés par les auteurs de la base de données. J'utilise Java client dans une application Scala avec succès.

la base de données est également très rapide - voici la comparaison scientifique avec d'autres bases de données (mettant de côté un aspect d'être un db spatial): http://airccse.org/journal/ijdms/papers/6314ijdms01.pdf

1
répondu Wojciech Kaczmarek 2016-09-07 08:59:52

j'aimerais partager un exemple de code Java pour Redis Geography edition.

public void geoadd(String objectId, BigDecimal latitude, BigDecimal longitude) {
    log.info("geoadd(): {} {} {}", objectId, latitude, longitude);
    try (Jedis jedis = jedisPool.getResource()) {
        if (geoaddSha == null) {
            String script = "return redis.call('geoadd','" + GEOSET + "', ARGV[1], ARGV[2], KEYS[1])";
            geoaddSha = jedis.scriptLoad(script);
        }
        log.info("geoaddSha: {}", geoaddSha);
        log.info(jedis.evalsha(geoaddSha, 1, objectId, latitude.toString(), longitude.toString()).toString());
    }
}

@SuppressWarnings("unchecked")
public List<String> georadius(BigDecimal latitude, BigDecimal longitude, int radius, Unit unit) {
    log.info("georadius(): {} {} {} {}", latitude, longitude, radius, unit);
    try (Jedis jedis = jedisPool.getResource()) {
        if (georadiusSha == null) {
            String script = "return redis.call('georadius','" + GEOSET + "', ARGV[1], ARGV[2], ARGV[3], ARGV[4])";
            georadiusSha = jedis.scriptLoad(script);
        }
        log.info("georadiusSha: {}", georadiusSha);
        List<String> objectIdList = (List<String>) jedis.evalsha(georadiusSha, 0, latitude.toString(), longitude.toString(), String.valueOf(radius), unit.toString());
        log.info("objectIdList: {}", objectIdList);
        return objectIdList;
    }
}

public void remove(String objectId) {
    log.info("remove(): {}", objectId);
    try (Jedis jedis = jedisPool.getResource()) {
        jedis.zrem(GEOSET, objectId);
    }
}
0
répondu Trinsit Wasinudomrod 2015-08-20 06:00:58