Maison >développement back-end >tutoriel php >Apprenez à utiliser PHP pour trouver les personnes à proximité que vous souhaitez

Apprenez à utiliser PHP pour trouver les personnes à proximité que vous souhaitez

藏色散人
藏色散人avant
2020-10-22 11:49:254653parcourir

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 :

Apprenez à utiliser PHP pour trouver les personnes à proximité que vous souhaitez

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);
    }

Le code MySQL est le suivant :

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;

En plus de l'obtenir en calculant la formule de distance sphérique ci-dessus, on peut utiliser un certain Certains services de bases de données sont disponibles, comme Redis et MongoDB :

Redis 3.2 fournit une fonction de localisation géographique GEO, qui peut non seulement obtenir la distance entre deux emplacements, mais également obtenir la collecte d'informations géographiques dans la plage de localisation spécifiée.

Documentation de la commande Redis

1. Ajouter un emplacement géographique

GEOADD key longitude latitude member [longitude latitude member ...]

2 Obtenir un emplacement géographique

GEOPOS key member [member ...]

3 Obtenir la distance entre deux emplacements géographiques
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 MongoDB

1. Ajouter des données

db.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" } } )

Méthodes PHP multiples et implémentations spécifiques

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 = &#39;INSERT INTO `markers`(`uin`, `lon`, `lat`) VALUES (?, ?, ?)&#39;;
    $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

redis

ou 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[&#39;:lat&#39;] = $lat;
    $input[&#39;:lon&#39;] = $lon;

    if ($where) {
        $sqlWhere = &#39; WHERE &#39;;
        foreach ($where as $key => $value) {
            $sqlWhere .= "`{$key}` = :{$key} ,";
            $input[":{$key}"] = $value;
        }
        $sql .= rtrim($sqlWhere, &#39;,&#39;);
    }

    if ($maxDistance) {
        $sqlHaving = " HAVING distance < :maxDistance";
        $sql .= $sqlHaving;
        $input[&#39;:maxDistance&#39;] = $maxDistance;
    }

    $sql .= &#39; ORDER BY distance&#39;;

    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;
}
Interroger les personnes à proximité (les conditions de requête et la pagination ne sont pas prises en charge) :

public function geoAdd($uin, $lon, $lat)
{
    $redis = $this->getRedis();
    $redis->geoAdd(&#39;markers&#39;, $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 = &#39;km&#39;)
{
    $redis = $this->getRedis();
    $options = [&#39;WITHDIST&#39;]; //显示距离
    $list = $redis->geoRadiusByMember(&#39;markers&#39;, $uin, $maxDistance, $unit, $options);
    return $list;
}

Méthode d'ajout de membres :

db.getCollection(&#39;location&#39;).ensureIndex({"uin":1},{"unique":true}) 
db.getCollection(&#39;location&#39;).ensureIndex({loc:"2d"})
#若查询位置附带查询,可以将常查询条件添加至组合索引
#db.getCollection(&#39;location&#39;).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(
        &#39;uin&#39; => $uin,
        &#39;loc&#39; => array(
            &#39;lon&#39; =>  $lon,
            &#39;lat&#39; =>  $lat,
        ),
    );

    $bulk = new MongoDB\Driver\BulkWrite;
    $bulk->update(
        [&#39;uin&#39; => $uin],
        $document,
        [ &#39;upsert&#39; => 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(&#39;db.location&#39;, $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(
        &#39;loc&#39; => array(
            &#39;$near&#39; => array($lon, $lat),
        ),
    );
    if ($maxDistance) {
        $filter[&#39;loc&#39;][&#39;$maxDistance&#39;] = $maxDistance;
    }
    if ($where) {
        $filter = array_merge($filter, $where);
    }
    $options = array();
    if ($page) {
        $page > 1 ? $skip = ($page - 1) * $this->pageCount : $skip = 0;
        $options = [
            &#39;limit&#39; => $this->pageCount,
            &#39;skip&#39; => $skip
        ];
    }

    $query = new MongoDB\Driver\Query($filter, $options);
    $manager = $this->getMongoManager();
    $cursor = $manager->executeQuery(&#39;db.location&#39;, $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 :

démo

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer