আমি গ্যাব্রিয়েলক এবং লিঙ্কযুক্ত ব্লগ পোস্টের উত্তরটি ডাটাবেস সূচকগুলি ব্যবহার করে এবং প্রকৃত দূরত্ব গণনার সংখ্যাকে হ্রাস করে সংশোধন করব ।
যদি আপনি ব্যবহারকারীর স্থানাঙ্কগুলি জানেন এবং আপনি সর্বাধিক দূরত্বটি (10 কিলোমিটার বলুন) জানেন তবে আপনি মাঝের বর্তমান অবস্থানের সাথে 20 কিলোমিটার অবধি 20 কিমি দৈর্ঘ্যের একটি বক্স আঁকতে পারেন। এই সীমাবদ্ধ স্থানাঙ্ক এবং কেবলমাত্র এই অক্ষাংশ এবং দ্রাঘিমাংশের মধ্যে অনুসন্ধান করুন । আপনার ডাটাবেস ক্যোয়ারিতে এখনও ত্রিকোণমিতি ফাংশন ব্যবহার করবেন না, কারণ এটি সূচকগুলি ব্যবহার হতে বাধা দেবে। (সুতরাং আপনি যদি বাউন্ডিং বাক্সের উত্তর-পূর্ব কোণে থাকেন তবে আপনার কাছ থেকে 12 কিলোমিটার দূরের কোনও স্টোর আপনি পেতে পারেন, তবে আমরা এটি পরবর্তী ধাপে ফেলে দেব))
ফিরে আসা কয়েকটি স্টোরের জন্য কেবল দূরত্বটি গণনা করুন (পাখিটি যেমন উড়ে বা আসল ড্রাইভিং নির্দেশিকাগুলি সহ, যেমন আপনি পছন্দ করেন) for আপনার যদি প্রচুর পরিমাণে স্টোর থাকে তবে এটি প্রক্রিয়াকরণের সময়টিকে তীব্রভাবে উন্নত করবে।
সম্পর্কিত অনুসন্ধানের জন্য ( "দশটি নিকটস্থ স্টোর দিন") ) আপনি একই ধরণের অনুসন্ধান করতে পারেন তবে প্রাথমিক দূরত্ব অনুমানের সাথে (তাই আপনি 10 কিলোমিটার এলাকা দিয়ে 10 কিলোমিটার এলাকা দিয়ে শুরু করেন, এবং আপনার কাছে পর্যাপ্ত স্টোর না থাকলে আপনি এটিকে প্রসারিত করুন) 20 কিমি বাই 20 কিমি এবং আরও কিছু)। এই প্রাথমিক দূরত্ব অনুমানের জন্য আপনি একবার মোট ক্ষেত্রের উপরে স্টোরের সংখ্যা গণনা করুন এবং এটি ব্যবহার করুন। অথবা প্রয়োজনীয় প্রশ্নের সংখ্যা লগ করুন এবং সময়ের সাথে মানিয়ে নিন।
আমি মাইকের সম্পর্কিত প্রশ্নে একটি পূর্ণ কোড উদাহরণ যুক্ত করেছি , এবং এখানে একটি এক্সটেনশন যা আপনাকে নিকটতম এক্স অবস্থান দেয় (দ্রুত এবং সবেমাত্র পরীক্ষিত):
class Monkeyman_Geo_ClosestX extends Monkeyman_Geo
{
public static $closestXStartDistanceKm = 10;
public static $closestXMaxDistanceKm = 1000; // Don't search beyond this
public function addAdminPages()
{
parent::addAdminPages();
add_management_page( 'Location closest test', 'Location closest test', 'edit_posts', __FILE__ . 'closesttest', array(&$this, 'doClosestTestPage'));
}
public function doClosestTestPage()
{
if (!array_key_exists('search', $_REQUEST)) {
$default_lat = ini_get('date.default_latitude');
$default_lon = ini_get('date.default_longitude');
echo <<<EOF
<form action="" method="post">
<p>Number of posts: <input size="5" name="post_count" value="10"/></p>
<p>Center latitude: <input size="10" name="center_lat" value="{$default_lat}"/>
<br/>Center longitude: <input size="10" name="center_lon" value="{$default_lon}"/></p>
<p><input type="submit" name="search" value="Search!"/></p>
</form>
EOF;
return;
}
$post_count = intval($_REQUEST['post_count']);
$center_lon = floatval($_REQUEST['center_lon']);
$center_lat = floatval($_REQUEST['center_lat']);
var_dump(self::getClosestXPosts($center_lon, $center_lat, $post_count));
}
/**
* Get the closest X posts to a given location
*
* This might return more than X results, and never more than
* self::$closestXMaxDistanceKm away (to prevent endless searching)
* The results are sorted by distance
*
* The algorithm starts with all locations no further than
* self::$closestXStartDistanceKm, and then grows this area
* (by doubling the distance) until enough matches are found.
*
* The number of expensive calculations should be minimized.
*/
public static function getClosestXPosts($center_lon, $center_lat, $post_count)
{
$search_distance = self::$closestXStartDistanceKm;
$close_posts = array();
while (count($close_posts) < $post_count && $search_distance < self::$closestXMaxDistanceKm) {
list($north_lat, $east_lon, $south_lat, $west_lon) = self::getBoundingBox($center_lat, $center_lon, $search_distance);
$geo_posts = self::getPostsInBoundingBox($north_lat, $east_lon, $south_lat, $west_lon);
foreach ($geo_posts as $geo_post) {
if (array_key_exists($geo_post->post_id, $close_posts)) {
continue;
}
$post_lat = floatval($geo_post->lat);
$post_lon = floatval($geo_post->lon);
$post_distance = self::calculateDistanceKm($center_lat, $center_lon, $post_lat, $post_lon);
if ($post_distance < $search_distance) {
// Only include those that are in the the circle radius, not bounding box, otherwise we might miss some closer in the next step
$close_posts[$geo_post->post_id] = $post_distance;
}
}
$search_distance *= 2;
}
asort($close_posts);
return $close_posts;
}
}
$monkeyman_Geo_ClosestX_instace = new Monkeyman_Geo_ClosestX();