5

It would be extremely helpful if an "order_by" & "sort" parameter could be passed in the api querystring.

"order_by" should accept the following options: distance | checkins | name

"sort" should accept the following options: asc | desc

The matched result set should have the order_by and sort parameters applied prior to narrowing the result set to the max "50" results that get returned.

Is this on the foursquare radar or is it something that will not be offered?

We are building an app that lets users locate "restaurants" closest to them based on the device's geolocation.

The issue we are having is in setting the default radius. We started by setting the radius to 3200 meters, hoping that that would return at lease some results for sparse locations while also returning the closest results for dense locations.

This works for locations that return less than 50 because we can sort post response, but in a dense area such as Washington DC, when there are more than 50 results the 50 that the api decides to return are NOT the closest to the ll.

Therefore we have to structure our query as shown below (which sucks cause it requires upto 7 hits to the api) to try to find that "sweet spot" of just under 50 results.

This is the issue we are encountering for "near me" locations in our app. We have a similar issue when trying to display "popular" venues in the app, but I'll save that for another post.

ob_start();
require_once 'includes/EpiCurl.php';
require_once 'includes/EpiFoursquare.php';
$clientId = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx';
$clientSecret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
$fsObjUnAuth = new EpiFoursquare($clientId, $clientSecret);

$time_start2 = microtime(true);

$result = $fsObjUnAuth->get('/venues/search', array(
'categoryId' => '4d4b7105d754a06374d81259',
'limit' => '50',
'radius' => '100',
'intent' => 'checkin',
'll' => $ll,
'v' => '20120211'
));
$result_count1 = count($result->response->venues);

if ($result_count1 < 30) {

    $result = $fsObjUnAuth->get('/venues/search', array(
        'categoryId' => '4d4b7105d754a06374d81259',
        'limit' => '50',
        'radius' => '200',
        'intent' => 'checkin',
        'll' => $ll,
        'v' => '20120211'
        ));

    $result_count2 = count($result->response->venues);

    if ($result_count2 < 30) {

        $result = $fsObjUnAuth->get('/venues/search', array(
            'categoryId' => '4d4b7105d754a06374d81259',
            'limit' => '50',
            'radius' => '400',
            'intent' => 'checkin',
            'll' => $ll,
            'v' => '20120211'
            ));

        $result_count3 = count($result->response->venues);

        if ($result_count3 < 30) {

            $result = $fsObjUnAuth->get('/venues/search', array(
                'categoryId' => '4d4b7105d754a06374d81259',
                'limit' => '50',
                'radius' => '800',
                'intent' => 'checkin',
                'll' => $ll,
                'v' => '20120211'
                ));
            $result_count4 = count($result->response->venues);

            if ($result_count4 < 30) {

                $result = $fsObjUnAuth->get('/venues/search', array(
                    'categoryId' => '4d4b7105d754a06374d81259',
                    'limit' => '50',
                    'radius' => '1200',
                    'intent' => 'checkin',
                    'll' => $ll,
                    'v' => '20120211'
                    ));

                $result_count5 = count($result->response->venues);

                if ($result_count5 < 30) {                
                    $result = $fsObjUnAuth->get('/venues/search', array(
                        'categoryId' => '4d4b7105d754a06374d81259',
                        'limit' => '50',
                        'radius' => '1600',
                        'intent' => 'checkin',
                        'll' => $ll,
                        'v' => '20120211'
                        ));
                    $result_count6 = count($result->response->venues);

                    if ($result_count6 < 30) {

                        $result = $fsObjUnAuth->get('/venues/search', array(
                            'categoryId' => '4d4b7105d754a06374d81259',
                            'limit' => '50',
                            'radius' => '3200',
                            'intent' => 'checkin',
                            'll' => $ll,
                            'v' => '20120211'
                            ));
                        $result_count7 = count($result->response->venues);
                    }
                }
            }
        }
    }
}
Samuel Harmer
  • 4,264
  • 5
  • 33
  • 67
Robert Hughes
  • 51
  • 1
  • 3

1 Answers1

1

There's no plan to offer such parameters. For the most part, these parameters are only useful for developers scraping all venues in a region, which is in violation of the foursquare terms of service

There are three different "intents" offered which correspond to valid use cases requiring different types of ranking.

  • intent=checkin returns a list of venues where the user is most likely is located

  • intent=browse returns a list of most relevant venues for a requested region, not biased by distance from a central point.

  • intent=match returns a single result that, with high confidence, is the corresponding foursquare venue for the query-based request

akdotcom
  • 4,627
  • 2
  • 17
  • 16
  • I understand foursquare's concern about someone scraping the database, however the 50 max results, pretty much eliminates that issue to the casual scraper. I've edited my question above to better explain my dilemma. – Robert Hughes Mar 03 '12 at 00:55
  • Can you give an example where the top results being returned are particularly far from the specified lat/lng? intent=checkin aggressively demotes results based on distance, so the results should be close to the specified lat/lng, while otherwise balancing for venue popularity (e.g. If the user is standing next to a hot dog stand outside a popular restaurant, the popular restaurant will be returned first). The current ranking is measurably more relevant for users, especially when the requesting device does not have a precise lock on the user's exact location. – akdotcom Mar 05 '12 at 15:30
  • Starting with 38.897758,-77.055286, which is the exact ll of 600 New Hampshire Ave NW, Washington, DC 20037, and also the exact address of 3 known venues in your database. If I set the radius to 100, the api finds less than 50 and I get the expected results: venues/search?ll=38.897758,-77.055286&radius=100&limit=50&categoryId=4d4b7105d754a06374d81259&intent=checkin&v=20120211 1. Cup'a Cup'a 2. Rivers at the Watergate 3. 600 Restaurant at the Watergate – Robert Hughes Mar 05 '12 at 16:06
  • If I set the radius to 3200, None of the 3 venues above are returned. As a matter of fact, the closest venue returned is 814 meters away. It seems as though the api returns the farthest away rather than the closest. venues/search?ll=38.897758,-77.055286&radius=3200&limit=50&categoryId=4d4b7105d754a06374d81259&intent=checkin&v=20120211 – Robert Hughes Mar 05 '12 at 16:07
  • Checked with the team -- we do retrieval from our index differently when handling category restrict queries. When restricting with category, there's a stronger bias towards popular venues, which is why these less popular venues right next to the user aren't being returned. This is at a retrieval level, so additional sort/order-by parameters won't actually help. – akdotcom Mar 06 '12 at 22:09
  • I agree this is frustrating, but your best solution is probably to first try making a category-less (and radius-less) query and filter the results on your end. If that fails, only then would I use a category restrict. – akdotcom Mar 06 '12 at 22:10