0
# Geographic and Places
1
2
Location-based functionality including places, geocoding, and geographic search.
3
4
## Places and Geographic Data
5
6
### Place Search and Discovery
7
8
Search for places and geographic locations.
9
10
```java { .api }
11
interface PlacesGeoResources {
12
/**
13
* Search for places matching query
14
* @param query Geographic query with location and search parameters
15
* @return List of matching places
16
*/
17
ResponseList<Place> searchPlaces(GeoQuery query) throws TwitterException;
18
19
/**
20
* Find similar places to a location
21
* @param location Geographic coordinates
22
* @param name Place name to search for
23
* @param containedWithin Place ID that should contain the result
24
* @param streetAddress Street address for more precise matching
25
* @return List of similar places
26
*/
27
ResponseList<Place> getSimilarPlaces(GeoLocation location, String name,
28
String containedWithin, String streetAddress) throws TwitterException;
29
30
/**
31
* Reverse geocoding - find places near coordinates
32
* @param query Geographic query with coordinates
33
* @return List of places near the coordinates
34
*/
35
ResponseList<Place> reverseGeoCode(GeoQuery query) throws TwitterException;
36
37
/**
38
* Get detailed information about a specific place
39
* @param placeId Twitter place ID
40
* @return Detailed place information
41
*/
42
Place getGeoDetails(String placeId) throws TwitterException;
43
}
44
```
45
46
**Usage Examples:**
47
48
```java
49
TwitterV1 v1 = twitter.v1();
50
51
// Search for places by name
52
GeoQuery query = GeoQuery.of("San Francisco")
53
.accuracy(GeoQuery.Accuracy.city)
54
.granularity("city")
55
.maxResults(10);
56
57
ResponseList<Place> places = v1.placesGeo().searchPlaces(query);
58
for (Place place : places) {
59
System.out.println(place.getFullName() + " (" + place.getId() + ")");
60
}
61
62
// Reverse geocoding - find places near coordinates
63
GeoLocation sanFrancisco = new GeoLocation(37.7749, -122.4194);
64
GeoQuery reverseQuery = GeoQuery.of(sanFrancisco)
65
.accuracy("1km")
66
.granularity("neighborhood");
67
68
ResponseList<Place> nearbyPlaces = v1.placesGeo().reverseGeoCode(reverseQuery);
69
for (Place place : nearbyPlaces) {
70
System.out.println("Nearby: " + place.getName());
71
}
72
73
// Get details for a specific place
74
Place placeDetails = v1.placesGeo().getGeoDetails("5a110d312052166f");
75
System.out.println("Full name: " + placeDetails.getFullName());
76
System.out.println("Country: " + placeDetails.getCountry());
77
System.out.println("Place type: " + placeDetails.getPlaceType());
78
```
79
80
## Geographic Query Building
81
82
### GeoQuery Class
83
84
Construct geographic search queries with location and filtering parameters.
85
86
```java { .api }
87
class GeoQuery {
88
/**
89
* Create query with place name
90
* @param query Place name or address to search for
91
* @return GeoQuery with search term
92
*/
93
static GeoQuery of(String query);
94
95
/**
96
* Create query with coordinates
97
* @param location Geographic coordinates
98
* @return GeoQuery with location
99
*/
100
static GeoQuery of(GeoLocation location);
101
102
/**
103
* Create query with coordinates and IP address
104
* @param location Geographic coordinates
105
* @param ip IP address for additional context
106
* @return GeoQuery with location and IP
107
*/
108
static GeoQuery of(GeoLocation location, String ip);
109
110
/**
111
* Set search accuracy
112
* @param accuracy Accuracy level or distance (e.g., "1km", "5mi")
113
* @return GeoQuery with accuracy setting
114
*/
115
GeoQuery accuracy(String accuracy);
116
117
/**
118
* Set search accuracy using predefined levels
119
* @param accuracy Predefined accuracy level
120
* @return GeoQuery with accuracy setting
121
*/
122
GeoQuery accuracy(Accuracy accuracy);
123
124
/**
125
* Set place granularity
126
* @param granularity Granularity level ("poi", "neighborhood", "city", "admin", "country")
127
* @return GeoQuery with granularity setting
128
*/
129
GeoQuery granularity(String granularity);
130
131
/**
132
* Set maximum number of results
133
* @param maxResults Maximum number of places to return
134
* @return GeoQuery with max results setting
135
*/
136
GeoQuery maxResults(int maxResults);
137
138
/**
139
* Set contained within constraint
140
* @param containedWithin Place ID that should contain results
141
* @return GeoQuery with containment constraint
142
*/
143
GeoQuery containedWithin(String containedWithin);
144
145
/**
146
* Set street address for more precise matching
147
* @param streetAddress Street address
148
* @return GeoQuery with address constraint
149
*/
150
GeoQuery streetAddress(String streetAddress);
151
152
/**
153
* Predefined accuracy levels
154
*/
155
enum Accuracy {
156
/** Point of interest level */
157
poi,
158
/** Neighborhood level */
159
neighborhood,
160
/** City level */
161
city,
162
/** Administrative level */
163
admin,
164
/** Country level */
165
country
166
}
167
}
168
```
169
170
### GeoLocation Class
171
172
Represent geographic coordinates.
173
174
```java { .api }
175
class GeoLocation {
176
/**
177
* Create location with latitude and longitude
178
* @param latitude Latitude in decimal degrees
179
* @param longitude Longitude in decimal degrees
180
*/
181
GeoLocation(double latitude, double longitude);
182
183
/**
184
* Get latitude
185
* @return Latitude in decimal degrees
186
*/
187
double getLatitude();
188
189
/**
190
* Get longitude
191
* @return Longitude in decimal degrees
192
*/
193
double getLongitude();
194
195
/**
196
* Calculate distance to another location
197
* @param other Other location
198
* @return Distance in kilometers
199
*/
200
double distanceTo(GeoLocation other);
201
202
/**
203
* Get string representation in "lat,lon" format
204
*/
205
@Override
206
String toString();
207
}
208
```
209
210
**Geographic Query Examples:**
211
212
```java
213
// Search for coffee shops in New York
214
GeoQuery coffeeQuery = GeoQuery.of("coffee")
215
.containedWithin("01a9a39529b27f36") // New York City place ID
216
.granularity("poi")
217
.maxResults(20);
218
219
ResponseList<Place> coffeeShops = v1.placesGeo().searchPlaces(coffeeQuery);
220
221
// Find neighborhoods within 2km of coordinates
222
GeoLocation myLocation = new GeoLocation(40.7128, -74.0060);
223
GeoQuery neighborhoodQuery = GeoQuery.of(myLocation)
224
.accuracy("2km")
225
.granularity("neighborhood");
226
227
ResponseList<Place> neighborhoods = v1.placesGeo().reverseGeoCode(neighborhoodQuery);
228
229
// Search for places with specific address
230
GeoQuery addressQuery = GeoQuery.of("Twitter HQ")
231
.streetAddress("1355 Market St, San Francisco, CA")
232
.granularity("poi");
233
234
ResponseList<Place> locations = v1.placesGeo().searchPlaces(addressQuery);
235
```
236
237
## Place Data Model
238
239
### Place Interface
240
241
Complete place information and geographic metadata.
242
243
```java { .api }
244
interface Place extends TwitterResponse {
245
/**
246
* Unique place identifier
247
*/
248
String getId();
249
250
/**
251
* Place name
252
*/
253
String getName();
254
255
/**
256
* Full place name (includes parent places)
257
*/
258
String getFullName();
259
260
/**
261
* Country where place is located
262
*/
263
String getCountry();
264
265
/**
266
* Country code (ISO 3166-1 alpha-2)
267
*/
268
String getCountryCode();
269
270
/**
271
* Place type ("poi", "neighborhood", "city", "admin", "country")
272
*/
273
String getPlaceType();
274
275
/**
276
* URL for place information
277
*/
278
String getURL();
279
280
/**
281
* Geographic bounding box for place
282
* @return Array of coordinate pairs defining the bounding box
283
*/
284
GeoLocation[][] getBoundingBoxCoordinates();
285
286
/**
287
* Bounding box type (usually "Polygon")
288
*/
289
String getBoundingBoxType();
290
291
/**
292
* Places that contain this place
293
* @return Array of parent/containing places
294
*/
295
Place[] getContainedWithin();
296
297
/**
298
* Additional place attributes
299
* @return Map of attribute keys to values
300
*/
301
Map<String, String> getAttributes();
302
303
/**
304
* Street address (if available)
305
*/
306
String getStreetAddress();
307
308
/**
309
* Locality/city name
310
*/
311
String getLocality();
312
313
/**
314
* Administrative region (state/province)
315
*/
316
String getRegion();
317
318
/**
319
* ISO country code
320
*/
321
String getIso3();
322
323
/**
324
* Postal code
325
*/
326
String getPostalCode();
327
328
/**
329
* Phone number (if available)
330
*/
331
String getPhone();
332
333
/**
334
* Twitter handle (if place has associated account)
335
*/
336
String getTwitter();
337
338
/**
339
* App ID that created this place (if applicable)
340
*/
341
String getAppId();
342
}
343
```
344
345
## Location-based Tweet Operations
346
347
### Geotagging Tweets
348
349
Add location information to tweets.
350
351
```java
352
// Create status update with location
353
GeoLocation tweetLocation = new GeoLocation(37.7749, -122.4194);
354
StatusUpdate statusWithLocation = StatusUpdate.of("Tweeting from San Francisco!")
355
.location(tweetLocation)
356
.displayCoordinates(true)
357
.placeId("5a110d312052166f"); // San Francisco place ID
358
359
Status geoTaggedTweet = v1.tweets().updateStatus(statusWithLocation);
360
361
System.out.println("Tweet location: " + geoTaggedTweet.getGeoLocation());
362
System.out.println("Tweet place: " + geoTaggedTweet.getPlace().getFullName());
363
```
364
365
### Location-based Search
366
367
Search for tweets near specific locations.
368
369
```java
370
// Search for tweets near San Francisco
371
GeoLocation sf = new GeoLocation(37.7749, -122.4194);
372
String geocode = sf.getLatitude() + "," + sf.getLongitude() + ",10km";
373
374
Query locationQuery = Query.of("food")
375
.geocode(geocode)
376
.count(100);
377
378
QueryResult results = v1.search().search(locationQuery);
379
380
for (Status tweet : results.getTweets()) {
381
if (tweet.getGeoLocation() != null) {
382
System.out.println("@" + tweet.getUser().getScreenName() + " from " +
383
tweet.getGeoLocation().toString() + ": " + tweet.getText());
384
}
385
386
if (tweet.getPlace() != null) {
387
System.out.println("Place: " + tweet.getPlace().getFullName());
388
}
389
}
390
```
391
392
## Advanced Geographic Operations
393
394
### Place Hierarchy Navigation
395
396
```java
397
public class PlaceHierarchy {
398
private final TwitterV1 v1;
399
400
public List<Place> getPlaceHierarchy(String placeId) throws TwitterException {
401
List<Place> hierarchy = new ArrayList<>();
402
Place currentPlace = v1.placesGeo().getGeoDetails(placeId);
403
404
hierarchy.add(currentPlace);
405
406
// Walk up the containment hierarchy
407
while (currentPlace.getContainedWithin() != null &&
408
currentPlace.getContainedWithin().length > 0) {
409
Place parent = currentPlace.getContainedWithin()[0];
410
hierarchy.add(parent);
411
412
// Get full details for parent
413
currentPlace = v1.placesGeo().getGeoDetails(parent.getId());
414
}
415
416
return hierarchy;
417
}
418
419
public void printPlaceHierarchy(String placeId) throws TwitterException {
420
List<Place> hierarchy = getPlaceHierarchy(placeId);
421
422
System.out.println("Place hierarchy (specific to general):");
423
for (int i = 0; i < hierarchy.size(); i++) {
424
Place place = hierarchy.get(i);
425
String indent = " ".repeat(i);
426
System.out.println(indent + place.getName() + " (" + place.getPlaceType() + ")");
427
}
428
}
429
}
430
```
431
432
### Geographic Bounding Box Operations
433
434
```java
435
public class GeoBoundingBox {
436
437
public static boolean isLocationInPlace(GeoLocation location, Place place) {
438
GeoLocation[][] boundingBox = place.getBoundingBoxCoordinates();
439
if (boundingBox == null || boundingBox.length == 0) {
440
return false;
441
}
442
443
// Simple bounding box check (assumes rectangular box)
444
GeoLocation[] box = boundingBox[0];
445
if (box.length < 2) return false;
446
447
double minLat = Math.min(box[0].getLatitude(), box[1].getLatitude());
448
double maxLat = Math.max(box[0].getLatitude(), box[1].getLatitude());
449
double minLon = Math.min(box[0].getLongitude(), box[1].getLongitude());
450
double maxLon = Math.max(box[0].getLongitude(), box[1].getLongitude());
451
452
return location.getLatitude() >= minLat && location.getLatitude() <= maxLat &&
453
location.getLongitude() >= minLon && location.getLongitude() <= maxLon;
454
}
455
456
public static GeoLocation getBoundingBoxCenter(Place place) {
457
GeoLocation[][] boundingBox = place.getBoundingBoxCoordinates();
458
if (boundingBox == null || boundingBox.length == 0) {
459
return null;
460
}
461
462
GeoLocation[] box = boundingBox[0];
463
if (box.length < 2) return null;
464
465
double centerLat = (box[0].getLatitude() + box[1].getLatitude()) / 2;
466
double centerLon = (box[0].getLongitude() + box[1].getLongitude()) / 2;
467
468
return new GeoLocation(centerLat, centerLon);
469
}
470
}
471
```
472
473
### Location-based Analytics
474
475
```java
476
public class LocationAnalytics {
477
private final TwitterV1 v1;
478
479
public Map<String, Integer> analyzeTweetsByLocation(String searchQuery,
480
GeoLocation center,
481
String radius) throws TwitterException {
482
String geocode = center.getLatitude() + "," + center.getLongitude() + "," + radius;
483
484
Query query = Query.of(searchQuery)
485
.geocode(geocode)
486
.count(100)
487
.resultType(Query.ResultType.recent);
488
489
QueryResult results = v1.search().search(query);
490
Map<String, Integer> locationCounts = new HashMap<>();
491
492
for (Status tweet : results.getTweets()) {
493
String location = "Unknown";
494
495
if (tweet.getPlace() != null) {
496
location = tweet.getPlace().getFullName();
497
} else if (tweet.getUser().getLocation() != null &&
498
!tweet.getUser().getLocation().trim().isEmpty()) {
499
location = tweet.getUser().getLocation();
500
}
501
502
locationCounts.merge(location, 1, Integer::sum);
503
}
504
505
return locationCounts.entrySet().stream()
506
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
507
.collect(Collectors.toMap(
508
Map.Entry::getKey,
509
Map.Entry::getValue,
510
(e1, e2) -> e1,
511
LinkedHashMap::new
512
));
513
}
514
515
public List<Place> findPopularPlacesNear(GeoLocation location, String radius)
516
throws TwitterException {
517
GeoQuery query = GeoQuery.of(location)
518
.accuracy(radius)
519
.granularity("poi")
520
.maxResults(50);
521
522
ResponseList<Place> places = v1.placesGeo().reverseGeoCode(query);
523
524
// Sort by some popularity metric (you might need additional data)
525
return places.stream()
526
.sorted((p1, p2) -> p1.getName().compareTo(p2.getName()))
527
.collect(Collectors.toList());
528
}
529
}
530
```
531
532
## Error Handling
533
534
Common geographic API errors and handling:
535
536
```java
537
try {
538
GeoQuery query = GeoQuery.of("Unknown Place Name");
539
ResponseList<Place> places = v1.placesGeo().searchPlaces(query);
540
541
if (places.isEmpty()) {
542
System.out.println("No places found matching the query");
543
}
544
} catch (TwitterException e) {
545
switch (e.getStatusCode()) {
546
case 400:
547
System.out.println("Invalid geographic query parameters");
548
break;
549
case 404:
550
System.out.println("Place not found");
551
break;
552
case 429:
553
System.out.println("Rate limit exceeded for geo API");
554
break;
555
default:
556
System.out.println("Geo API error: " + e.getMessage());
557
}
558
}
559
560
try {
561
Place place = v1.placesGeo().getGeoDetails("invalid_place_id");
562
} catch (TwitterException e) {
563
if (e.getStatusCode() == 404) {
564
System.out.println("Place ID does not exist");
565
}
566
}
567
```
568
569
## Best Practices
570
571
### Geographic Data Privacy
572
573
- Always respect user privacy when handling location data
574
- Check if users have enabled geotagging before using location info
575
- Be aware that precise coordinates may be sensitive information
576
- Consider using place-level location instead of exact coordinates
577
578
### Performance Optimization
579
580
- Cache place lookups to avoid repeated API calls
581
- Use appropriate granularity levels for your use case
582
- Batch geographic queries when possible
583
- Consider using bounding boxes for area-based searches
584
585
### Data Quality
586
587
- Validate coordinates before making API calls
588
- Handle cases where geographic data may be incomplete
589
- Cross-reference place data with user-provided location strings
590
- Be prepared for varying levels of geographic precision