Récemment, il y a eu un scénario commercial qui permettait de trouver des personnes à proximité, j'ai donc vérifié les informations pertinentes et examiné l'utilisation de PHP pour implémenter les fonctions associées. Un résumé technique des différentes méthodes et implémentations spécifiques est fait. Les commentaires et corrections sont les bienvenus. Passons maintenant au point :
LBS (service basé sur la localisation)
La recherche de personnes à proximité a un terme plus large appelé LBS (service basé sur la localisation). LBS fait référence à l'obtention d'informations de localisation des utilisateurs de terminaux mobiles via le réseau de communication radio des opérateurs de télécommunications mobiles ou des méthodes de positionnement externes avec le support du SIG. plateforme, il s’agit d’un service à valeur ajoutée qui fournit aux utilisateurs les services correspondants. Par conséquent, la position de l'utilisateur doit être obtenue en premier. La position de l'utilisateur peut être obtenue par GPS, station de base de l'opérateur, WIFI, etc. Généralement, le client obtient les coordonnées de longitude et de latitude de la position de l'utilisateur et les télécharge sur le serveur d'application. Le serveur d'applications enregistre les coordonnées de l'utilisateur et du client. Lors de l'obtention des données des personnes à proximité, le serveur d'applications accède à la base de données pour filtrer et trier en fonction de la situation géographique du demandeur et de certaines conditions (distance, sexe, durée d'activité, etc.).Comment trouver la distance entre deux points en fonction de la longitude et de la latitude ?
Nous savons tous que les coordonnées de deux points dans les coordonnées planes peuvent être calculées à l'aide de la formule de distance des coordonnées planes, mais la longitude et la latitude sont des systèmes de coordonnées sphériques qui utilisent la surface sphérique de l'espace tridimensionnel pour définir l'espace sur la terre. Supposons que la terre C'est une sphère droite. La formule pour calculer la distance sphérique est la suivante : Si vous êtes intéressé par le spécifique. processus d'inférence, je recommande cet article :[Formule mathématique et dérivation] Calculer la distance entre le sol et le sol en fonction de la longitude et de la latitude La distance entre les points
Le code de la fonction PHP est comme suit :/** * 根据两点间的经纬度计算距离 * @param $lat1 * @param $lng1 * @param $lat2 * @param $lng2 * @return float */ public static function getDistance($lat1, $lng1, $lat2, $lng2){ $earthRadius = 6367000; //approximate radius of earth in meters $lat1 = ($lat1 * pi() ) / 180; $lng1 = ($lng1 * pi() ) / 180; $lat2 = ($lat2 * pi() ) / 180; $lng2 = ($lng2 * pi() ) / 180; $calcLongitude = $lng2 - $lng1; $calcLatitude = $lat2 - $lat1; $stepOne = pow(sin($calcLatitude / 2), 2) + cos($lat1) * cos($lat2) * pow(sin($calcLongitude / 2), 2); $stepTwo = 2 * asin(min(1, sqrt($stepOne))); $calculatedDistance = $earthRadius * $stepTwo; return round($calculatedDistance); }
SELECT id, ( 3959 * acos ( cos ( radians(78.3232) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(65.3234) ) + sin ( radians(78.3232) ) * sin( radians( lat ) ) ) ) AS distance FROM markers HAVING distance < 30 ORDER BY distance LIMIT 0 , 20;
Documentation de la commande Redis
1. Ajouter un emplacement géographiqueGEOADD key longitude latitude member [longitude latitude member ...]
GEOPOS key member [member ...]
GEODIST key member1 member2 [unit]
4. Obtenez l'ensemble de localisation des informations géographiques de la longitude et de la latitude spécifiées
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
5. Obtenez l'ensemble de localisation des informations géographiques du membre spécifié
GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
MongoDB a établi un géospatial. index spécifiquement pour ce type de requête. Les index 2d et 2dsphere concernent respectivement les plans et les sphères.
Document MongoDBdb.location.insert( {uin : 1 , loc : { lon : 50 , lat : 50 } } )
2. Créer un index
db.location.ensureIndex( { loc : "2d" } )
3. Distance maximale et nombre limité d'éléments
db.location.find( { loc :{ $near : [50, 50] } )
5. Utilisez geoNear pour renvoyer la distance de chaque point du point de requête dans le résultat de la requête
db.location.find( { loc : { $near : [50, 50] , $maxDistance : 5 } } ).limit(20)
6. Utilisez geoNear avec les conditions de requête et le nombre. des éléments renvoyés, geoNear ne prend pas en charge la limite liée à la pagination et ignore les paramètres dans la requête de recherche lors de l'utilisation de la commande runCommand
db.runCommand( { geoNear : "location" , near : [ 50 , 50 ], num : 10, query : { type : "museum" } } )
1. Basé sur MySql Méthode d'ajout de membres :
db.runCommand( { geoNear : "location" , near : [ 50 , 50 ], num : 10, query : { uin : 1 } })
Interroger les personnes à proximité (prend en charge les conditions de requête et la pagination) :
public function geoAdd($uin, $lon, $lat) { $pdo = $this->getPdo(); $sql = 'INSERT INTO `markers`(`uin`, `lon`, `lat`) VALUES (?, ?, ?)'; $stmt = $pdo->prepare($sql); return $stmt->execute(array($uin, $lon, $lat)); }
2. Basé sur Redis (3.2 ou supérieur)
PHP utilise Redis Vous pouvez installer l'extension
redisou installer la bibliothèque de classes
predis via composer. Cet article utilise l'extension redis pour l'implémenter. Méthode d'ajout de membres : public function geoNearFind($lon, $lat, $maxDistance = 0, $where = array(), $page = 0)
{
$pdo = $this->getPdo();
$sql = "SELECT
id, (
3959 * acos (
cos ( radians(:lat) )
* cos( radians( lat ) )
* cos( radians( lon ) - radians(:lon) )
+ sin ( radians(:lat) )
* sin( radians( lat ) )
)
) AS distance
FROM markers";
$input[':lat'] = $lat;
$input[':lon'] = $lon;
if ($where) {
$sqlWhere = ' WHERE ';
foreach ($where as $key => $value) {
$sqlWhere .= "`{$key}` = :{$key} ,";
$input[":{$key}"] = $value;
}
$sql .= rtrim($sqlWhere, ',');
}
if ($maxDistance) {
$sqlHaving = " HAVING distance < :maxDistance";
$sql .= $sqlHaving;
$input[':maxDistance'] = $maxDistance;
}
$sql .= ' ORDER BY distance';
if ($page) {
$page > 1 ? $offset = ($page - 1) * $this->pageCount : $offset = 0;
$sqlLimit = " LIMIT {$offset} , {$this->pageCount}";
$sql .= $sqlLimit;
}
$stmt = $pdo->prepare($sql);
$stmt->execute($input);
$list = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $list;
}
public function geoAdd($uin, $lon, $lat) { $redis = $this->getRedis(); $redis->geoAdd('markers', $lon, $lat, $uin); return true; }
3. Basé sur MongoDB
PHP utilisant MongoDB Les extensions incluent
mongo(
Document) et mongodb(Document). Les méthodes d'écriture des deux sont très différentes. une bonne extension nécessite une correspondance Vérifiez la documentation. Puisque l'extension mongodb est une nouvelle version, cet article sélectionne l'extension mongodb. Supposons que nous créions la bibliothèque de base de données et la collection d'emplacements Définissons l'index :
public function geoNearFind($uin, $maxDistance = 0, $unit = 'km') { $redis = $this->getRedis(); $options = ['WITHDIST']; //显示距离 $list = $redis->geoRadiusByMember('markers', $uin, $maxDistance, $unit, $options); return $list; }
Méthode d'ajout de membres :
db.getCollection('location').ensureIndex({"uin":1},{"unique":true}) db.getCollection('location').ensureIndex({loc:"2d"}) #若查询位置附带查询,可以将常查询条件添加至组合索引 #db.getCollection('location').ensureIndex({loc:"2d",uin:1})
Requête des personnes à proximité (les résultats de retour ont pas de distance, prend en charge les conditions de requête, prend en charge la pagination)
public function geoAdd($uin, $lon, $lat) { $document = array( 'uin' => $uin, 'loc' => array( 'lon' => $lon, 'lat' => $lat, ), ); $bulk = new MongoDB\Driver\BulkWrite; $bulk->update( ['uin' => $uin], $document, [ 'upsert' => true] ); //出现noreply 可以改成确认式写入 $manager = $this->getMongoManager(); $writeConcern = new MongoDB\Driver\WriteConcern(1, 100); //$writeConcern = new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY, 100); $result = $manager->executeBulkWrite('db.location', $bulk, $writeConcern); if ($result->getWriteErrors()) { return false; } return true; }
Interroge les personnes à proximité (renvoie les résultats avec la distance, prend en charge les conditions de requête, la quantité de paiement retournée, ne prend pas en charge la pagination) :
public function geoNearFind($lon, $lat, $maxDistance = 0, $where = array(), $page = 0) { $filter = array( 'loc' => array( '$near' => array($lon, $lat), ), ); if ($maxDistance) { $filter['loc']['$maxDistance'] = $maxDistance; } if ($where) { $filter = array_merge($filter, $where); } $options = array(); if ($page) { $page > 1 ? $skip = ($page - 1) * $this->pageCount : $skip = 0; $options = [ 'limit' => $this->pageCount, 'skip' => $skip ]; } $query = new MongoDB\Driver\Query($filter, $options); $manager = $this->getMongoManager(); $cursor = $manager->executeQuery('db.location', $query); $list = $cursor->toArray(); return $list; }
Notes :
1. Choisissez une bonne extension Les méthodes d'écriture des extensions mongo et mongodb sont très différentes
2. Si aucune réponse n'apparaît lors de l'écriture des données, veuillez vérifier le niveau de confirmation d'écriture
3 Les données interrogées à l'aide de find doivent calculer la distance vous-même et les données interrogées à l'aide de geoNear ne prennent pas en charge la pagination
4. Utilisation La distance interrogée par geoNear doit être convertie en km à l'aide des paramètres sphérique et distanceMultiplier La démo ci-dessus peut être cliqué ici : RésuméCe qui précède présente trois types de méthodes pour implémenter la fonction d'interrogation des personnes à proximité. Chaque méthode a ses propres scénarios applicables, par exemple, il y a relativement peu de lignes de données. Par exemple, Mysql suffit pour interroger le. distance entre un utilisateur et plusieurs villes. Si vous avez besoin de répondre rapidement en temps réel et généralement Pour trouver la distance dans la plage, vous pouvez utiliser Redis, mais si la quantité de données est importante et qu'il existe plusieurs conditions de filtrage d'attributs, cela le fera. être plus pratique d'utiliser mongo. Ce qui précède ne sont que des suggestions. Le plan de mise en œuvre spécifique sera examiné en fonction de l'entreprise spécifique.Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!