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?
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
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.
Peut-être que vous pouvez essayer celui-ci:
Vous avez vraiment envie de l'essayer, ça fonctionne super. :)
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.
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):
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
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);
}
}