দুটি ল্যাট / দীর্ঘ পয়েন্টের মধ্যে দূরত্ব খুঁজে পাওয়ার দ্রুততম উপায়


227

আমার কাছে বর্তমানে দ্রাঘিমাংশ এবং অক্ষাংশের তথ্য সহ একটি মাইএসকিএল ডাটাবেজে এক মিলিয়ন অবস্থানের অধীনে রয়েছে।

আমি একটি প্রশ্নের মাধ্যমে একটি পয়েন্ট এবং অন্যান্য অনেক পয়েন্টের মধ্যে দূরত্বটি অনুসন্ধান করার চেষ্টা করছি। এটি যতটা দ্রুত আমি চাই না এটি বিশেষত ১০০+ এক সেকেন্ডের সাথে হিট হোক।

এর জন্য মাইএসকিএল ব্যতীত কোনও তাত্ক্ষণিক জিজ্ঞাসা বা সম্ভবত কোনও দ্রুততর সিস্টেম আছে? আমি এই ক্যোয়ারীটি ব্যবহার করছি:

SELECT 
  name, 
   ( 3959 * acos( cos( radians(42.290763) ) * cos( radians( locations.lat ) ) 
   * cos( radians(locations.lng) - radians(-71.35368)) + sin(radians(42.290763)) 
   * sin( radians(locations.lat)))) AS distance 
FROM locations 
WHERE active = 1 
HAVING distance < 10 
ORDER BY distance;

দ্রষ্টব্য: প্রদত্ত দূরত্বটি মাইলগুলিতে । আপনার যদি কিলোমিটারের প্রয়োজন হয় তবে তার 6371পরিবর্তে ব্যবহার করুন 3959


31
আপনার দেওয়া সূত্রটিতে মনে হচ্ছে প্রচুর উপাদান ধ্রুবক। আপনার ডিবিতে ডেটা প্রাক-গণনা এবং সেই মানগুলি সংরক্ষণ করা কি সম্ভব? উদাহরণস্বরূপ 3959 * অ্যাকোস (রেডিয়ানস (42.290763)) একটি ধ্রুবক তবে এতে 4 টি বড় গণনা রয়েছে comp পরিবর্তে আপনি কেবল 6696.7837 সঞ্চয় করতে পারবেন?
পিটার এম

1
বা কোয়েরির বাইরে কমপক্ষে প্রাক-গণনা ধ্রুবক? এটি করতে হবে যে কাজ কাটা হবে।
পিটার এম

2
@ পিটার এম সম্ভবত মনে হয় যে কোনও শালীন এসকিউএল ডাটাবেস অপ্টিমাইজ করবে যাতে এটি কেবল একবার গণনা করা হয়েছিল।
mhenry1384

25
যারা ভাবছেন তাদের পক্ষে, 42.290763 অক্ষাংশ এবং -71.35368 হল বিন্দুটির দ্রাঘিমাংশ যা থেকে দূরত্বগুলি গণনা করা হয়।
ব্যবহারকারী 276648

14
কেবল তথ্যের জন্য, এই সূত্র ধরে দূরত্বটি মাইল দূরে কিলোমিটারে নয় lease অনুগ্রহ করে কিলোমিটারে ফলাফল পেতে 3959 থেকে 6371 প্রতিস্থাপন করুন
সাহিল

উত্তর:


115

, বা, মধ্যে MySQL 5.1এবং উপরে:

    SELECT  *
    FROM    table
    WHERE   MBRContains
                    (
                    LineString
                            (
                            Point (
                                    @lon + 10 / ( 111.1 / COS(RADIANS(@lat))),
                                    @lat + 10 / 111.1
                                  ),
                            Point (
                                    @lon - 10 / ( 111.1 / COS(RADIANS(@lat))),
                                    @lat - 10 / 111.1
                                  ) 
                            ),
                    mypoint
                    )

এটি বাক্সের মধ্যে প্রায় সমস্ত পয়েন্ট নির্বাচন করবে (@lat +/- 10 km, @lon +/- 10km)

এটি আসলে একটি বাক্স নয়, একটি গোলাকার আয়তক্ষেত্র: গোলকের অক্ষাংশ এবং দ্রাঘিমাংশের আবদ্ধ অংশ। এটি ফ্রাঞ্জ জোসেফ ল্যান্ডের সমতল আয়তক্ষেত্র থেকে পৃথক হতে পারে তবে বেশিরভাগ আবাসিক স্থানে এটির খুব কাছে রয়েছে।

  • বৃত্তের ভিতরে সমস্ত কিছু বাছাই করতে অতিরিক্ত ফিল্টারিং প্রয়োগ করুন (বর্গ নয়)

  • বড় চেনাশোনা দূরত্বের জন্য অ্যাকাউন্টে অতিরিক্ত সূক্ষ্ম ফিল্টারিং সম্ভবত প্রয়োগ করুন (বড় দূরত্বের জন্য)


15
@ কাসনোই: একটি সংশোধন: আপনি সম্ভবত স্থানাঙ্কগুলির ক্রমটি দীর্ঘ, দীর্ঘায়িত করতে চাইবেন। এছাড়াও, দ্রাঘিমাংশীয় দূরত্বগুলি দ্রাঘিমাংশ নয়, অক্ষাংশের কোসাইন সমানুপাতিক । এবং আপনি এটিকে গুণ থেকে বিভাগে পরিবর্তন করতে চান, সুতরাং আপনার প্রথম স্থানাঙ্ক হিসাবে সংশোধন করা হবে @lon - 10 / ( 111.1 / cos(@lat))(এবং সবকিছু ঠিক হয়ে যাওয়ার পরে জোড়ায় দ্বিতীয় হবেন
এম। ডেভ আউয়ান ১১'১০ এ ৮:১০

8
সতর্কতা : উত্তর এমডি @ এম দ্বারা করা খুব বৈধ মন্তব্যের সাথে সামঞ্জস্য করা হয়নি। ডেভ আউয়ান আরও দ্রষ্টব্য: আগ্রহের বৃত্তটিতে (ক) একটি মেরু অন্তর্ভুক্ত থাকে বা (খ) দ্রাঘিমাংশের +/- 180 ডিগ্রি মেরিডিয়ান দ্বারা ছেদ করা থাকলে এই পদ্ধতিটি ছড়িয়ে পড়ে। এছাড়াও ব্যবহার cos(lon)কেবল ছোট দূরত্বের জন্য সঠিক। Janmatuschek.de/ স্পষ্টতা দ্রাঘিমাংশ সীমানা সমন্বয়
জন মাচিন

3
ধ্রুবকগুলি (10, 111.11, @ ল্যাট, @ লোন, মাইপয়েন্ট) প্রতিনিধিত্ব করে সেগুলির কি আমরা কিছুটা অন্তর্দৃষ্টি পেতে পারি? আমি ধরে নিলাম যে 10 টি কিলোমিটার দূরত্বের জন্য, @ ল্যাট এবং @ লোন প্রদত্ত ল্যাটিচ এবং দ্রাঘিমাংশকে উপস্থাপন করে, তবে 111.11 এবং মাইপয়েন্ট উদাহরণে কী উপস্থাপন করে?
21

4
@ অ্যাশয়েস: 111.(1)অক্ষাংশের এক ডিগ্রিতে প্রায় কি.মি. mypointটেবিলের ক্ষেত্রটি যা স্থানাঙ্কগুলি সঞ্চয় করে।
কাসনসুই

1
আরেকটি ত্রুটি সংশোধন - আপনি দ্বিতীয় একটি ক্লোজিং) গত লাইন অনুপস্থিত
আইএনএ

99

কোনও মাইএসকিউএল নির্দিষ্ট উত্তর নয়, তবে এটি আপনার স্ক্যাল স্টেটমেন্টের কার্যকারিতা উন্নত করবে।

আপনি কার্যকরভাবে যা করছেন তা সারণীর প্রতিটি পয়েন্টের দূরত্ব গণনা করা হচ্ছে এটি কোনও নির্দিষ্ট বিন্দুর 10 ইউনিটের মধ্যে রয়েছে কিনা তা দেখার জন্য।

আপনি এই স্কয়ারটি চালানোর আগে আপনি যা করতে পারেন তা হল চারটি পয়েন্ট যা একটি দিকে 20 বাক্স ইউনিট করে একটি বিন্দু তৈরি করবে, আপনার পয়েন্টটি কেন্দ্রে রাখবে। (এক্স 1, ওয়াই 1) । । (x4, y4), যেখানে (x1, y1) হয় (প্রদত্ত দীর্ঘ + 10 ইউনিট, প্রদত্ত ল্যাট + 10 ইউনিট)। । । (প্রদত্তলং - 10 ইউনাইটস, প্রদত্ত ল্যাট -10 ইউনিট)। আসলে, আপনার কেবল দুটি পয়েন্ট প্রয়োজন, উপরের বাম এবং নীচে ডান তাদের কল করুন (এক্স 1, ওয়াই 1) এবং (এক্স 2, ওয়াই 2)

এখন আপনার এসকিউএল স্টেটমেন্টটি আপনার প্রদত্ত বিন্দু থেকে অবশ্যই 10u এর বেশি সারিগুলি বাদ দেওয়ার জন্য এই পয়েন্টগুলি ব্যবহার করে, এটি অক্ষাংশ এবং দ্রাঘিমাংশগুলিতে সূচীগুলি ব্যবহার করতে পারে, সুতরাং আপনার বর্তমানের তুলনায় দ্রুততার আদেশ হবে।

যেমন

select . . . 
where locations.lat between X1 and X2 
and   locations.Long between y1 and y2;

বাক্সের পদ্ধতির ক্ষেত্রে মিথ্যা ধনাত্মকতা ফিরে আসতে পারে (আপনি প্রদত্ত বিন্দু থেকে> 10u বাক্সের কোণে পয়েন্টগুলি তুলতে পারেন), সুতরাং আপনাকে প্রতিটি পয়েন্টের দূরত্ব গণনা করতে হবে। তবে এটি আবার আরও দ্রুত হবে কারণ আপনি বাক্সের মধ্যে থাকা পয়েন্টগুলিতে পরীক্ষার জন্য পয়েন্টের সংখ্যা মারাত্মকভাবে সীমাবদ্ধ করেছেন।

আমি এই কৌশলটিকে "বাক্সের ভিতরে চিন্তাভাবনা" বলি :)

সম্পাদনা: এটি কি একটি এসকিউএল স্টেটমেন্টে রাখা যেতে পারে?

দুঃখিত, আমার মাইএসকিএল বা পিএইচপি কীভাবে সক্ষম তা সম্পর্কে আমার কোনও ধারণা নেই। আমি জানি না যে চারটি পয়েন্ট তৈরি করার জন্য সেরা জায়গাটি কীভাবে, বা কীভাবে পিএইচপিএইচএসএইচএল কোয়েরিতে সেগুলি দেওয়া যেতে পারে। যাইহোক, একবার আপনার চারটি পয়েন্ট হয়ে গেলে, আপনার নিজের এসকিউএল বিবৃতিটি আমার সাথে একত্রিত করার কোনও কারণ নেই।

select name, 
       ( 3959 * acos( cos( radians(42.290763) ) 
              * cos( radians( locations.lat ) ) 
              * cos( radians( locations.lng ) - radians(-71.35368) ) 
              + sin( radians(42.290763) ) 
              * sin( radians( locations.lat ) ) ) ) AS distance 
from locations 
where active = 1 
and locations.lat between X1 and X2 
and locations.Long between y1 and y2
having distance < 10 ORDER BY distance;

আমি জানি এমএস এসকিউএল-এর সাথে আমি একটি এসকিউএল স্টেটমেন্ট তৈরি করতে পারি যা চারটি ফ্লোট (এক্স 1, ওয়াই 1, এক্স 2, ওয়াই 2) ঘোষণা করে এবং "মুখ্য" নির্বাচনী বিবৃতিটির আগে সেগুলি গণনা করে, যেমন আমি বলেছিলাম, এটি করা যায় কিনা আমার কোনও ধারণা নেই মাইএসকিউএল। তবে আমি এখনও সি # তে চারটি পয়েন্ট তৈরি করতে এবং এসকিউএল কোয়েরিতে প্যারামিটার হিসাবে তাদের পাস করার জন্য ঝুঁকতে চাই।

দুঃখিত, আমি আরও সাহায্য হতে পারি না, যদি কেউ এর মাইএসকিউএল এবং পিএইচপি নির্দিষ্ট অংশের উত্তর দিতে পারে তবে এই উত্তরটি সম্পাদন করতে দ্বিধা বোধ করুন।


4
আপনি এই উপস্থাপনায় এই পদ্ধতির জন্য একটি মাইএসকিএল পদ্ধতি খুঁজে পেতে পারেন: scribd.com/doc/2569355/ জিও
লুসিয়া

37
মাইলের পরিবর্তে কিলোমিটার অনুসন্ধান করতে, 3959 প্রতিস্থাপন করুন 6371 দিয়ে।
এরিকবিএসচুল্জ

4
+1, দুর্দান্ত বিকল্প; বাক্সটি যুক্ত করা আমার ক্যোয়ারিকে 4 এস থেকে 0.03 এসিতে কমিয়েছে।
jvenema

1
এটিকে এত যুক্তিযুক্ত মনে হলেও আপনি এই সমাধানের জন্য একটি পুরষ্কার সংরক্ষণ করেন! ২ মিলিয়ন রেকর্ড ডাটাবেসে কোয়েরিটি 16 সেকেন্ড থেকে 0.06 সেকেন্ডে চলে গেছে। দ্রষ্টব্য: যদি আপনি কোয়েরি থেকে দূরত্ব গণনাটি কেটে ফেলে থাকেন এবং আপনার প্রোগ্রামের কোডের দূরত্বের জন্য গণনা করেন তবে এটি আরও দ্রুত (বৃহত টেবিলগুলির জন্য)!
এনএলানাকোন্ডা

2
@ বাইনারি ওয়ারিয়ার: সুতরাং এক্স 1, এক্স 2 এবং ওয়াই 1, ওয়াই 2 হ'ল দ্রাঘিমাংশ মিন এবং ম্যাক্স এবং অক্ষাংশ ন্যূনতম এবং ম্যাক্সটি এখানে দেওয়া উদাহরণ অনুসারে: ব্লগ.ফেডগার্গ . com / 2009 / 02 / 08/… দয়া করে পরামর্শ দিন।
প্রভাত

14

নিম্নলিখিত মাইএসকিউএল ফাংশনটি এই ব্লগ পোস্টে পোস্ট করা হয়েছিল । আমি এটি খুব বেশি পরীক্ষা করে দেখিনি, তবে পোস্ট থেকে যা সংগ্রহ করেছি তা থেকে, যদি আপনার অক্ষাংশ এবং দ্রাঘিমাংশ ক্ষেত্রগুলি সূচিযুক্ত হয় , তবে এটি আপনার পক্ষে ভাল কাজ করতে পারে:

DELIMITER $$

DROP FUNCTION IF EXISTS `get_distance_in_miles_between_geo_locations` $$
CREATE FUNCTION get_distance_in_miles_between_geo_locations(
  geo1_latitude decimal(10,6), geo1_longitude decimal(10,6), 
  geo2_latitude decimal(10,6), geo2_longitude decimal(10,6)) 
returns decimal(10,3) DETERMINISTIC
BEGIN
  return ((ACOS(SIN(geo1_latitude * PI() / 180) * SIN(geo2_latitude * PI() / 180) 
    + COS(geo1_latitude * PI() / 180) * COS(geo2_latitude * PI() / 180) 
    * COS((geo1_longitude - geo2_longitude) * PI() / 180)) * 180 / PI()) 
    * 60 * 1.1515);
END $$

DELIMITER ;

নমুনা ব্যবহার:

placesক্ষেত্রগুলির সাথে ডেকে একটি সারণী ধরে নেওয়া latitudeএবং longitude:

SELECT get_distance_in_miles_between_geo_locations(-34.017330, 22.809500,
latitude, longitude) AS distance_from_input FROM places;

আমি এটি চেষ্টা করেছি এবং এটি নিখুঁতভাবে কাজ করে, তবে কোনওভাবেই এটি আমাকে দূরত্ব_ফর্ম_পিন্ডের উপর ভিত্তি করে একটি WHERE বিবৃতি দেওয়ার অনুমতি দেয় না। কোন ধারণা নেই কেন?
ক্রিস দর্শক

আপনি এটি সাব-সিলেক্ট হিসাবে করতে পারেন: * থেকে (...) টি হিসাবে নির্বাচন করুন যেখানে দূরত্ব_ফর্ম_ ইনপুট> 5;
ব্র্যাড পার্কগুলি

2
বা কেবল এর সাথে সরাসরি যান: যে জায়গাগুলি থেকে_ দূরত্ব_মিনাইল_মাইল_সেটো_জিও_লোকেশন (-34.017330, 22.809500, অক্ষাংশ, দ্রাঘিমাংশ)> 5000 থেকে * নির্বাচন করুন;
ব্র্যাড পার্কগুলি

2
রিটার্ন মিটার:SELECT ROUND(((ACOS(SIN(lat1 * PI() / 180) * SIN(lat2 * PI() / 180) + COS(lat1 * PI() / 180) * COS(lat2 * PI() / 180) * COS((lnt1 - lnt2) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) * 1.609344 * 1000) AS distance
মোহাম্মদ

13

আমার অনুরূপ সমস্যাটি সমাধান করা দরকার (একক পয়েন্ট থেকে দূরত্বে সারিগুলি ছাঁকানো) এবং উত্তর এবং মন্তব্যের সাথে মূল প্রশ্নটি একত্রিত করে আমি এমন সমাধান নিয়ে এসেছি যা আমার জন্য MySQL 5.6 এবং 5.7 উভয় ক্ষেত্রে পুরোপুরি কাজ করে।

SELECT 
    *,
    (6371 * ACOS(COS(RADIANS(56.946285)) * COS(RADIANS(Y(coordinates))) 
    * COS(RADIANS(X(coordinates)) - RADIANS(24.105078)) + SIN(RADIANS(56.946285))
    * SIN(RADIANS(Y(coordinates))))) AS distance
FROM places
WHERE MBRContains
    (
    LineString
        (
        Point (
            24.105078 + 15 / (111.320 * COS(RADIANS(56.946285))),
            56.946285 + 15 / 111.133
        ),
        Point (
            24.105078 - 15 / (111.320 * COS(RADIANS(56.946285))),
            56.946285 - 15 / 111.133
        )
    ),
    coordinates
    )
HAVING distance < 15
ORDER By distance

coordinatesটাইপযুক্ত ক্ষেত্র POINTএবং SPATIALসূচকটি
6371হ'ল কিলোমিটারে দূরত্ব গণনা করার
56.946285জন্য কেন্দ্রীয় বিন্দুর
24.105078জন্য দ্রাঘিমাংশ হয় কেন্দ্রীয় বিন্দুর জন্য দ্রাঘিমাংশ
15কিলোমিটারে সর্বোচ্চ দূরত্ব

আমার পরীক্ষায়, মাইএসকিউএলগুলি coordinatesআয়তক্ষেত্রের মধ্যে থাকা সমস্ত সারিগুলি দ্রুত নির্বাচন করার জন্য মাঠে স্প্যাটিয়াল সূচক ব্যবহার করে এবং তারপরে আয়তাকার কোণ থেকে স্থানগুলি বাদ দিতে এবং সমস্ত বৃত্তের ভিতরে কেবল স্থানগুলি রেখে সমস্ত ফিল্টার করা জায়গাগুলির জন্য প্রকৃত দূরত্ব গণনা করে।

এটি আমার ফলাফলটির দৃশ্যায়ন:

মানচিত্র

ধূসর তারা তারা মানচিত্রে সমস্ত পয়েন্ট কল্পনা করে, হলুদ তারাগুলি মাইএসকিউএল কোয়েরি দ্বারা ফিরে আসে। আয়তক্ষেত্রের কোণগুলির ভিতরে ধূসর তারাগুলি (তবে বাইরের বৃত্তের) দ্বারা নির্বাচিত হয়েছিল MBRContains()এবং তারপরে HAVINGধারা দ্বারা নির্বাচিত করা হয়েছিল ।


এটি যথেষ্ট উত্সাহ দিতে পারে না। প্রায় 5 মিলিয়ন রেকর্ড সহ একটি টেবিলের মাধ্যমে অনুসন্ধান করা এবং এই পদ্ধতির সাহায্যে একটি স্থানিক সূচক অনুসন্ধানের সময়টি পুরানো এ 8 প্রসেসরের 0.005 সেকেন্ড। আমি জানি যে মাইলগুলিতে ফলাফল পেতে 3959 দিয়ে 6371 প্রতিস্থাপন করা যেতে পারে তবে 111.133 এবং 111.320 এর মানগুলি কি সামঞ্জস্য করা দরকার বা সেগুলি সর্বজনীন ধ্রুবক?
26:51

দুর্দান্ত সমাধান।
সিবিস্কুট

পয়েন্টটি কীভাবে তৈরি করবেন তা হল পয়েন্ট (ল্যাট, এলএনজি) বা পয়েন্ট (
এলএনজি

2
@ ব্যবহারকারী 606669 এটি পয়েন্ট (এলএনজি, ল্যাট)
মেরিস কিসেভস

এক্স () এবং ওয়াই () ফাংশনটি আজকাল ST_Y এবং ST_X হওয়া উচিত।
আন্দ্রেয়াস

11

আপনি যদি মাইএসকিউএল ৫. using ব্যবহার করেন তবে আপনি st_distance_sphere (POINT, POINT) ব্যবহার করতে পারেন ।

Select st_distance_sphere(POINT(-2.997065, 53.404146 ), POINT(58.615349, 23.56676 ))/1000  as distcance

1
এটি একটি খুব ভাল এবং পড়া সহজ বিকল্প। মনে রাখবেন, পয়েন্ট () এর প্যারামিটার অর্ডার হ'ল (এলএনজি, ল্যাট) অন্যথায় আপনি "ক্লোজ" দিয়ে শেষ করতে পারেন তবে এখনও অন্য পদ্ধতিতে খুব আলাদা ফলাফল পাবেন। দেখুন: স্ট্যাকওভারফ্লো.com
অ্যান্ডি পি

9
SELECT * FROM (SELECT *,(((acos(sin((43.6980168*pi()/180)) * 
sin((latitude*pi()/180))+cos((43.6980168*pi()/180)) * 
cos((latitude*pi()/180)) * cos(((7.266903899999988- longitude)* 
pi()/180))))*180/pi())*60*1.1515 ) as distance 
FROM wp_users WHERE 1 GROUP BY ID limit 0,10) as X 
ORDER BY ID DESC

এটি মাইএসকিউএল এর পয়েন্টগুলির মধ্যে দূরত্ব গণনার ক্যোয়ারী, আমি এটি একটি দীর্ঘ ডাটাবেসে ব্যবহার করেছি, এটি নিখুঁতভাবে কাজ করে! দ্রষ্টব্য: আপনার প্রয়োজনীয়তা অনুসারে পরিবর্তনগুলি (ডাটাবেসের নাম, টেবিলের নাম, কলাম ইত্যাদি) করুন।


1.1515 মানটি কী উপস্থাপন করে? আমি এর আগে একটি অনুরূপ সূত্র দেখেছি, তবে এটি 1.1515 এর পরিবর্তে 1.75 ব্যবহার করেছে।
ট্রাইহার্ডার

1
আমার নিজের প্রশ্নের জবাবে, আমি মনে করি উত্তর এখানে থাকা পারে stackoverflow.com/a/389251/691053
TryHarder

8
set @latitude=53.754842;
set @longitude=-2.708077;
set @radius=20;

set @lng_min = @longitude - @radius/abs(cos(radians(@latitude))*69);
set @lng_max = @longitude + @radius/abs(cos(radians(@latitude))*69);
set @lat_min = @latitude - (@radius/69);
set @lat_max = @latitude + (@radius/69);

SELECT * FROM postcode
WHERE (longitude BETWEEN @lng_min AND @lng_max)
AND (latitude BETWEEN @lat_min and @lat_max);

উৎস


11
আপনার উত্স উদ্ধৃত করুন। এটি হ'ল: blog.fedecarg.com/2009/02/08/…
redburn

এই ক্ষেত্রে 69 কি? আমাদের যদি পৃথিবী ব্যাসার্ধ থাকে তবে কীভাবে করবেন?
কোডআর্নার

2
1 ল্যাটিটুডে কিলোমিটার 111 কিলোমিটার। 1 ল্যাটিটুডে মাইল 69 মাইল। এবং 69 মাইল = 111 কিলোমিটার। এজন্য আমরা রূপান্তরগুলিতে প্যারামিটার ব্যবহার করেছি।
কোডআর্নার

আমি চিরকাল এটি খুঁজছিলাম। এটি এত সহজ হতে পারে জানেন না। তোমাকে অনেক ধন্যবাদ.
বিকাশ

এটি কি lng_min / lng_max ব্যাসার্ধের গণিতে ল্যাট_মিন এবং ল্যাট_ম্যাক্স ব্যবহার করা দরকার বলে ভুল হবে না?
বেন

6
   select
   (((acos(sin(('$latitude'*pi()/180)) * sin((`lat`*pi()/180))+cos(('$latitude'*pi()/180)) 
    * cos((`lat`*pi()/180)) * cos((('$longitude'- `lng`)*pi()/180))))*180/pi())*60*1.1515) 
    AS distance
    from table having distance<22;

5

একটি মাইএসকিউএল ফাংশন যা দুটি স্থানাঙ্কের মধ্যে মিটার সংখ্যা প্রদান করে:

CREATE FUNCTION DISTANCE_BETWEEN (lat1 DOUBLE, lon1 DOUBLE, lat2 DOUBLE, lon2 DOUBLE)
RETURNS DOUBLE DETERMINISTIC
RETURN ACOS( SIN(lat1*PI()/180)*SIN(lat2*PI()/180) + COS(lat1*PI()/180)*COS(lat2*PI()/180)*COS(lon2*PI()/180-lon1*PI()/180) ) * 6371000

ভিন্ন ফর্ম্যাটে মানটি ফিরিয়ে আনার 6371000জন্য, ইউনিটের পছন্দ অনুযায়ী পৃথিবীর ব্যাসার্ধের সাথে ফাংশনটির প্রতিস্থাপন করুন । উদাহরণস্বরূপ, কিলোমিটার হবে 6371এবং মাইল হবে 3959

ফাংশনটি ব্যবহার করতে, কেবল মাইএসকিউএলে অন্য কোনও ফাংশন হিসাবে এটি কল করুন। উদাহরণস্বরূপ, যদি আপনার কোনও টেবিল থাকে তবে আপনি cityপ্রতিটি শহর থেকে অন্য প্রতিটি শহরের মধ্যে দূরত্ব খুঁজে পেতে পারেন:

SELECT
    `city1`.`name`,
    `city2`.`name`,
    ROUND(DISTANCE_BETWEEN(`city1`.`latitude`, `city1`.`longitude`, `city2`.`latitude`, `city2`.`longitude`)) AS `distance`
FROM
    `city` AS `city1`
JOIN
    `city` AS `city2`

4

মাইএসকিউএল প্লাগইন হিসাবে কীভাবে ইনস্টল করবেন সে সম্পর্কে বিশদ সহ পুরো কোডটি এখানে রয়েছে: https://github.com/lucasepe/lib_mysqludf_haversine

আমি মন্তব্য হিসাবে এই গত বছর পোস্ট। যেহেতু বিনয়ী @ টাইলারকলার আমাকে উত্তর হিসাবে পোস্ট করার পরামর্শ দিয়েছেন, এটি এখানে।

আরেকটি উপায় হ'ল একটি কাস্টম ইউডিএফ ফাংশন লিখুন যা দুটি পয়েন্ট থেকে হ্যাওয়ারসাইন দূরত্ব ফিরিয়ে দেয়। এই ফাংশনটি ইনপুট নিতে পারে:

lat1 (real), lng1 (real), lat2 (real), lng2 (real), type (string - optinal - 'km', 'ft', 'mi')

সুতরাং আমরা এই জাতীয় কিছু লিখতে পারি:

SELECT id, name FROM MY_PLACES WHERE haversine_distance(lat1, lng1, lat2, lng2) < 40;

40 কিলোমিটার কম দূরত্বে সমস্ত রেকর্ড আনতে। বা:

SELECT id, name FROM MY_PLACES WHERE haversine_distance(lat1, lng1, lat2, lng2, 'ft') < 25;

25 ফুটের কম দূরত্বে সমস্ত রেকর্ড আনতে।

মূল ফাংশনটি হ'ল:

double
haversine_distance( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error ) {
    double result = *(double*) initid->ptr;
    /*Earth Radius in Kilometers.*/ 
    double R = 6372.797560856;
    double DEG_TO_RAD = M_PI/180.0;
    double RAD_TO_DEG = 180.0/M_PI;
    double lat1 = *(double*) args->args[0];
    double lon1 = *(double*) args->args[1];
    double lat2 = *(double*) args->args[2];
    double lon2 = *(double*) args->args[3];
    double dlon = (lon2 - lon1) * DEG_TO_RAD;
    double dlat = (lat2 - lat1) * DEG_TO_RAD;
    double a = pow(sin(dlat * 0.5),2) + 
        cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD) * pow(sin(dlon * 0.5),2);
    double c = 2.0 * atan2(sqrt(a), sqrt(1-a));
    result = ( R * c );
    /*
     * If we have a 5th distance type argument...
     */
    if (args->arg_count == 5) {
        str_to_lowercase(args->args[4]);
        if (strcmp(args->args[4], "ft") == 0) result *= 3280.8399;
        if (strcmp(args->args[4], "mi") == 0) result *= 0.621371192;
    }

    return result;
}

3

একটি দ্রুত, সরল এবং নির্ভুল (ছোট দূরত্বের জন্য) একটি স্ফুলিঙ্গীয় অভিক্ষেপ দিয়ে প্রায় অনুমান করা যায় । কমপক্ষে আমার রাউটিং অ্যালগরিদমে আমি সঠিক গণনার তুলনায় 20% বৃদ্ধি পেয়েছি। জাভা কোডে এটি দেখতে মনে হচ্ছে:

public double approxDistKm(double fromLat, double fromLon, double toLat, double toLon) {
    double dLat = Math.toRadians(toLat - fromLat);
    double dLon = Math.toRadians(toLon - fromLon);
    double tmp = Math.cos(Math.toRadians((fromLat + toLat) / 2)) * dLon;
    double d = dLat * dLat + tmp * tmp;
    return R * Math.sqrt(d);
}

মাইএসকিউএল সম্পর্কে নিশ্চিত নয় (দুঃখিত!)।

আপনি সীমাবদ্ধতা সম্পর্কে নিশ্চিত হন তা নিশ্চিত হয়ে নিন (assertEquals এর তৃতীয় পরম মানে কিলোমিটারে নির্ভুলতা):

    float lat = 24.235f;
    float lon = 47.234f;
    CalcDistance dist = new CalcDistance();
    double res = 15.051;
    assertEquals(res, dist.calcDistKm(lat, lon, lat - 0.1, lon + 0.1), 1e-3);
    assertEquals(res, dist.approxDistKm(lat, lon, lat - 0.1, lon + 0.1), 1e-3);

    res = 150.748;
    assertEquals(res, dist.calcDistKm(lat, lon, lat - 1, lon + 1), 1e-3);
    assertEquals(res, dist.approxDistKm(lat, lon, lat - 1, lon + 1), 1e-2);

    res = 1527.919;
    assertEquals(res, dist.calcDistKm(lat, lon, lat - 10, lon + 10), 1e-3);
    assertEquals(res, dist.approxDistKm(lat, lon, lat - 10, lon + 10), 10);

3

এখানে মাইএসকিউএল এর সাথে জিও দূরত্ব অনুসন্ধানের একটি খুব বিশদ বিবরণ হ্যাভারসাইন সূত্রটি মাইএসকিএল-এর প্রয়োগের ভিত্তিতে একটি সমাধান রয়েছে। তত্ত্ব, বাস্তবায়ন এবং আরও কর্মক্ষমতা অপ্টিমাইজেশন সহ সম্পূর্ণ সমাধানের বিবরণ। যদিও স্থানগত অপ্টিমাইজেশান অংশটি আমার ক্ষেত্রে সঠিকভাবে কাজ করে নি। http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL


3

মাইএসকিউএলের সাথে জিও দূরত্ব অনুসন্ধানের একটি পড়ুন, মাইএসকিউএল-এ হ্যাভারসাইন সূত্রটি প্রয়োগের উপর ভিত্তি করে একটি সমাধান। এটি তত্ত্ব, বাস্তবায়ন এবং আরও কার্যকারিতা অপ্টিমাইজেশন সহ সম্পূর্ণ সমাধানের বিবরণ। যদিও স্থানগত অপ্টিমাইজেশান অংশটি আমার ক্ষেত্রে সঠিকভাবে কাজ করে নি।

আমি এতে দুটি ভুল লক্ষ্য করেছি:

  1. absp8 এ সিলেক্ট স্টেটমেন্টে ব্যবহার করুন। আমি কেবল বাদ দিয়েছি absএবং এটি কাজ করেছে।

  2. p27- তে স্থানিক অনুসন্ধানের দূরত্ব ফাংশনটি রেডিয়ানে রূপান্তরিত করে না বা দ্রাঘিমাংশ দ্বারা দৈর্ঘ্যকে রূপান্তর করে না cos(latitude), যদি না তার স্থানিক তথ্য বিবেচনার সাথে বোঝানো হয় (নিবন্ধের প্রেক্ষাপট থেকে বলতে পারে না), তবে p26 এ তার উদাহরণ ইঙ্গিত দেয় যে তার স্থানিক ডেটা POINTলোড হয় না রেডিয়ান বা ডিগ্রি


0
$objectQuery = "SELECT table_master.*, ((acos(sin((" . $latitude . "*pi()/180)) * sin((`latitude`*pi()/180))+cos((" . $latitude . "*pi()/180)) * cos((`latitude`*pi()/180)) * cos(((" . $longitude . "- `longtude`)* pi()/180))))*180/pi())*60*1.1515  as distance FROM `table_post_broadcasts` JOIN table_master ON table_post_broadcasts.master_id = table_master.id WHERE table_master.type_of_post ='type' HAVING distance <='" . $Radius . "' ORDER BY distance asc";

0

মাইএসকিএল ব্যবহার করে

SET @orig_lon = 1.027125;
SET @dest_lon = 1.027125;

SET @orig_lat = 2.398441;
SET @dest_lat = 2.398441;

SET @kmormiles = 6371;-- for distance in miles set to : 3956

SELECT @kmormiles * ACOS(LEAST(COS(RADIANS(@orig_lat)) * 
 COS(RADIANS(@dest_lat)) * COS(RADIANS(@orig_lon - @dest_lon)) + 
 SIN(RADIANS(@orig_lat)) * SIN(RADIANS(@dest_lat)),1.0)) as distance;

দেখুন: https://andrew.hedges.name/experiments/haversine/

দেখুন: https://stackoverflow.com/a/24372831/5155484

দেখুন: http://www.plumislandmedia.net/mysql/haversine-mysql-narerest-loc/

দ্রষ্টব্য: https://stackoverflow.com/a/24372831/5155484 এLEAST দেওয়া পরামর্শ হিসাবে নাল মানগুলি এড়ানোর জন্য ব্যবহৃত হয়

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.