factual-api 1.2 → 1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +10 -0
- data/README.md +14 -615
- data/lib/factual.rb +18 -4
- data/lib/factual/api.rb +27 -3
- data/lib/factual/query/crosswalk.rb +14 -2
- data/lib/factual/query/match.rb +19 -0
- metadata +55 -47
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -3,8 +3,6 @@
|
|
3
3
|
This is the Factual supported Ruby driver for [Factual's public API](http://developer.factual.com/display/docs/Factual+Developer+APIs+Version+3).
|
4
4
|
|
5
5
|
|
6
|
-
This driver is supported via the [Factual Developer Group](https://groups.google.com/group/factual_developers)
|
7
|
-
|
8
6
|
# Overview
|
9
7
|
|
10
8
|
## Basic Design
|
@@ -24,11 +22,19 @@ Results are returned as Ruby Arrays of Hashes, where each Hash is a result recor
|
|
24
22
|
|
25
23
|
## Setup
|
26
24
|
|
27
|
-
The driver's gems are hosted at [Rubygems.org](http://rubygems.org).
|
25
|
+
The driver's gems are hosted at [Rubygems.org](http://rubygems.org).
|
26
|
+
|
27
|
+
You can install the factual-api gem as follows:
|
28
28
|
|
29
|
-
|
29
|
+
````bash
|
30
30
|
$ gem install factual-api
|
31
|
-
|
31
|
+
````
|
32
|
+
|
33
|
+
Or add one line to the Gemfile of your Rails project, and run `bundle`:
|
34
|
+
|
35
|
+
````ruby
|
36
|
+
gem 'factual-api'
|
37
|
+
````
|
32
38
|
|
33
39
|
Once the gem is installed, you can use it in your Ruby project like:
|
34
40
|
|
@@ -138,616 +144,6 @@ query.rows # return many rows
|
|
138
144
|
query.total_count
|
139
145
|
````
|
140
146
|
|
141
|
-
# Read API
|
142
|
-
|
143
|
-
## All Top Level Query Parameters
|
144
|
-
|
145
|
-
<table>
|
146
|
-
<col width="33%"/>
|
147
|
-
<col width="33%"/>
|
148
|
-
<col width="33%"/>
|
149
|
-
<tr>
|
150
|
-
<th>Parameter</th>
|
151
|
-
<th>Description</th>
|
152
|
-
<th>Example</th>
|
153
|
-
</tr>
|
154
|
-
<tr>
|
155
|
-
<td>filters</td>
|
156
|
-
<td>Restrict the data returned to conform to specific conditions.</td>
|
157
|
-
<td><tt>query = query.filters("name" => {"$bw" => "starbucks"})</tt></td>
|
158
|
-
</tr>
|
159
|
-
<tr>
|
160
|
-
<td>get total row count</td>
|
161
|
-
<td>returns the total count of the number of rows in the dataset that conform to the query.</td>
|
162
|
-
<td><tt>query.total_count</tt></td>
|
163
|
-
</tr>
|
164
|
-
<tr>
|
165
|
-
<td>geo</td>
|
166
|
-
<td>Restrict data to be returned to be within a geographical range based.</td>
|
167
|
-
<td>(See the section on Geo Filters)</td>
|
168
|
-
</tr>
|
169
|
-
<tr>
|
170
|
-
<td>limit</td>
|
171
|
-
<td>Limit the results</td>
|
172
|
-
<td><tt>query = query.limit(12)</tt></td>
|
173
|
-
</tr>
|
174
|
-
<tr>
|
175
|
-
<td>page</td>
|
176
|
-
<td>Limit the results to a specific "page".</td>
|
177
|
-
<td><tt>query = query.page(2, :per => 10)</tt></td>
|
178
|
-
</tr>
|
179
|
-
<tr>
|
180
|
-
<td>search (across entity)</td>
|
181
|
-
<td>Full text search across entity</td>
|
182
|
-
<td>
|
183
|
-
Find "sushi":<br><tt>query = query.search("sushi")</tt><p>
|
184
|
-
Find "sushi" or "sashimi":<br><tt>query = query.search("sushi", "sashimi")</tt><p>
|
185
|
-
Find "sushi" and "santa" and "monica":<br><tt>query.search("sushi santa monica")</tt>
|
186
|
-
</td>
|
187
|
-
</tr>
|
188
|
-
<tr>
|
189
|
-
<td>search (across field)</td>
|
190
|
-
<td>Full text search on specific field</td>
|
191
|
-
<td><tt>query = query.filters({"name" => {"$search" => "cafe"}})</tt></td>
|
192
|
-
</tr>
|
193
|
-
<tr>
|
194
|
-
<td>select</td>
|
195
|
-
<td>Specifiy which fields to include in the query results. Note that the order of fields will not necessarily be preserved in the resulting response due to the nature Hashes.</td>
|
196
|
-
<td><tt>query = query.select(:name, :address, :locality, :region)</tt></td>
|
197
|
-
</tr>
|
198
|
-
<tr>
|
199
|
-
<td>sort</td>
|
200
|
-
<td>The field (or fields) to sort data on, as well as the direction of sort.<p>
|
201
|
-
Sorts ascending by default, but supports both explicitly sorting ascending and descending, by using <tt>sort_asc</tt> or <tt>sort_desc</tt>.
|
202
|
-
Supports $distance as a sort option if a geo-filter is specified.<p>
|
203
|
-
Supports $relevance as a sort option if a full text search is specified either using the q parameter or using the $search operator in the filter parameter.<p>
|
204
|
-
By default, any query with a full text search will be sorted by relevance.<p>
|
205
|
-
Any query with a geo filter will be sorted by distance from the reference point. If both a geo filter and full text search are present, the default will be relevance followed by distance.</td>
|
206
|
-
<td><tt>query = query.sort("name")</tt><br>
|
207
|
-
<tt>query = query.sort_desc("$distance")</tt>
|
208
|
-
<tt>query = query.sort_asc("name").sort_desc("rating")</tt></td>
|
209
|
-
</tr>
|
210
|
-
</table>
|
211
|
-
|
212
|
-
## Row Filters
|
213
|
-
|
214
|
-
The driver supports various row filter logic. For example:
|
215
|
-
|
216
|
-
`````ruby
|
217
|
-
# Returns records from the Places dataset with names beginning with "starbucks"
|
218
|
-
factual.table("places").filters("name" => {"$bw" => "starbucks"}).rows
|
219
|
-
````
|
220
|
-
|
221
|
-
### Supported row filter logic
|
222
|
-
|
223
|
-
<table>
|
224
|
-
<tr>
|
225
|
-
<th>Predicate</th>
|
226
|
-
<th width="25%">Description</th>
|
227
|
-
<th>Example</th>
|
228
|
-
</tr>
|
229
|
-
<tr>
|
230
|
-
<td>$eq</td>
|
231
|
-
<td>equal to</td>
|
232
|
-
<td><tt>query = query.filters("region" => {"$eq" => "CA"})</tt></td>
|
233
|
-
</tr>
|
234
|
-
<tr>
|
235
|
-
<td>$neq</td>
|
236
|
-
<td>not equal to</td>
|
237
|
-
<td><tt>query = query.filters("region" => {"$neq" => "CA"})</tt></td>
|
238
|
-
</tr>
|
239
|
-
<tr>
|
240
|
-
<td>search</td>
|
241
|
-
<td>full text search</td>
|
242
|
-
<td><tt>query = query.search("sushi")</tt></td>
|
243
|
-
</tr>
|
244
|
-
<tr>
|
245
|
-
<td>$in</td>
|
246
|
-
<td>equals any of</td>
|
247
|
-
<td><tt>query = query.filters("region" => {"$in" => ["CA", "NM", "NY"]})</tt></td>
|
248
|
-
</tr>
|
249
|
-
<tr>
|
250
|
-
<td>$nin</td>
|
251
|
-
<td>does not equal any of</td>
|
252
|
-
<td><tt>query = query.filters("region" => {"$nin" => ["CA", "NM", "NY"]})</tt></td>
|
253
|
-
</tr>
|
254
|
-
<tr>
|
255
|
-
<td>$bw</td>
|
256
|
-
<td>begins with</td>
|
257
|
-
<td><tt>query = query.filters("name" => {"$bw" => "starbucks"})</tt></td>
|
258
|
-
</tr>
|
259
|
-
<tr>
|
260
|
-
<td>$nbw</td>
|
261
|
-
<td>does not begin with</td>
|
262
|
-
<td><tt>query = query.filters("name" => {"$nbw" => "starbucks"})</tt></td>
|
263
|
-
</tr>
|
264
|
-
<tr>
|
265
|
-
<td>$bwin</td>
|
266
|
-
<td>begins with any of</td>
|
267
|
-
<td><tt>query = query.filters("name" => {"$bwin" => ["starbucks", "coffee", "tea"]})</tt></td>
|
268
|
-
</tr>
|
269
|
-
<tr>
|
270
|
-
<td>$nbwin</td>
|
271
|
-
<td>does not begin with any of</td>
|
272
|
-
<td><tt>query = query.filters("name" => {"$nbwin" => ["starbucks", "coffee", "tea"]})</tt></td>
|
273
|
-
</tr>
|
274
|
-
<tr>
|
275
|
-
<td>$blank</td>
|
276
|
-
<td>test to see if a value is (or is not) blank or null</td>
|
277
|
-
<td><tt>query = query.filters("tel" => {"$blank" => true})</tt><br>
|
278
|
-
<tt>query = query.filters("website" => {"$blank" => false})</tt></td>
|
279
|
-
</tr>
|
280
|
-
<tr>
|
281
|
-
<td>$gt</td>
|
282
|
-
<td>greater than</td>
|
283
|
-
<td><tt>query = query.filters("rating" => {"$gt" => 7.5})</tt></td>
|
284
|
-
</tr>
|
285
|
-
<tr>
|
286
|
-
<td>$gte</td>
|
287
|
-
<td>greater than or equal</td>
|
288
|
-
<td><tt>query = query.filters("rating" => {"$gte" => 7.5})</tt></td>
|
289
|
-
</tr>
|
290
|
-
<tr>
|
291
|
-
<td>$lt</td>
|
292
|
-
<td>less than</td>
|
293
|
-
<td><tt>query = query.filters("rating" => {"$lt" => 7.5})</tt></td>
|
294
|
-
</tr>
|
295
|
-
<tr>
|
296
|
-
<td>$lte</td>
|
297
|
-
<td>less than or equal</td>
|
298
|
-
<td><tt>query = query.filters("rating" => {"$lte" => 7.5})</tt></td>
|
299
|
-
</tr>
|
300
|
-
</table>
|
301
|
-
|
302
|
-
### AND
|
303
|
-
|
304
|
-
Filters can be logically AND'd together. For example:
|
305
|
-
|
306
|
-
````ruby
|
307
|
-
# name begins with "coffee" AND tel is not blank
|
308
|
-
query = query.filters({ "$and" => [{"name" => {"$bw" => "coffee"}}, {"tel" => {"$blank" => false}}] })
|
309
|
-
````
|
310
|
-
|
311
|
-
### OR
|
312
|
-
|
313
|
-
Filters can be logically OR'd. For example:
|
314
|
-
|
315
|
-
````ruby
|
316
|
-
# name begins with "coffee" OR tel is not blank
|
317
|
-
query = query.filters({ "$or" => [{"name" => {"$bw" => "coffee"}}, {"tel" => {"$blank" => false}}] })
|
318
|
-
````
|
319
|
-
|
320
|
-
### Combined ANDs and ORs
|
321
|
-
|
322
|
-
You can nest AND and OR logic to whatever level of complexity you need. For example:
|
323
|
-
|
324
|
-
````ruby
|
325
|
-
# (name begins with "Starbucks") OR (name begins with "Coffee")
|
326
|
-
# OR
|
327
|
-
# (name full text search matches on "tea" AND tel is not blank)
|
328
|
-
query = query.filters({ "$or" => [ {"$or" => [ {"name" => {"$bw" => "starbucks"}},
|
329
|
-
{"name" => {"$bw" => "coffee"}}]},
|
330
|
-
{"$and" => [ {"name" => {"$search" => "tea"}},
|
331
|
-
{"tel" => {"$blank" => false}} ]} ]})
|
332
|
-
````
|
333
|
-
|
334
|
-
# Crosswalk
|
335
|
-
|
336
|
-
The driver fully supports Factual's Crosswalk feature, which lets you "crosswalk" the web and relate entities between Factual's data and that of other web authorities.
|
337
|
-
|
338
|
-
(See [the Crosswalk Blog](http://blog.factual.com/crosswalk-api) for more background.)
|
339
|
-
|
340
|
-
## Simple Crosswalk Example
|
341
|
-
|
342
|
-
````ruby
|
343
|
-
# Get all Crosswalk data for a Place with a specific FactualID
|
344
|
-
factual.crosswalk("110ace9f-80a7-47d3-9170-e9317624ebd9").rows
|
345
|
-
````
|
346
|
-
|
347
|
-
## Supported Crosswalk Options
|
348
|
-
|
349
|
-
### only
|
350
|
-
|
351
|
-
You can specify which namespaces you want, like this:
|
352
|
-
|
353
|
-
````ruby
|
354
|
-
# Get Crosswalk data for only yelp and facebook for a Place with a specific FactualID
|
355
|
-
factual.crosswalk("110ace9f-80a7-47d3-9170-e9317624ebd9").only(:yelp, :facebook).rows
|
356
|
-
````
|
357
|
-
|
358
|
-
This will generally return 1 record per requested namespace.
|
359
|
-
|
360
|
-
### limit
|
361
|
-
|
362
|
-
You can limit the amount of Crosswalk results you get back, like this:
|
363
|
-
|
364
|
-
````ruby
|
365
|
-
# Get only 3 Crosswalk results for a Place with a specific FactualID
|
366
|
-
factual.crosswalk("110ace9f-80a7-47d3-9170-e9317624ebd9").limit(3).rows
|
367
|
-
````
|
368
|
-
|
369
|
-
# Resolve
|
370
|
-
|
371
|
-
The driver fully supports Factual's Resolve feature, which lets you start with incomplete data you may have for an entity, and get potential entity matches back from Factual.
|
372
|
-
|
373
|
-
Each result record will include a confidence score (<tt>"similarity"</tt>), and a flag indicating whether Factual decided the entity is the correct resolved match with a high degree of accuracy (<tt>"resolved"</tt>).
|
374
|
-
|
375
|
-
For any Resolve query, there will be 0 or 1 entities returned with <tt>"resolved"=true</tt>. If there was a full match, it is guaranteed to be the first record in the response Array.
|
376
|
-
|
377
|
-
(See [the Resolve Blog](http://blog.factual.com/factual-resolve) for more background.)
|
378
|
-
|
379
|
-
## Simple Resolve Examples
|
380
|
-
|
381
|
-
````ruby
|
382
|
-
# Returns resolved entities as an array of hashes
|
383
|
-
query = factual.resolve("name" => "McDonalds",
|
384
|
-
"address" => "10451 Santa Monica Blvd",
|
385
|
-
"region" => "CA",
|
386
|
-
"postcode" => "90025")
|
387
|
-
|
388
|
-
query.first["resolved"] # true or false
|
389
|
-
query.rows # all candidate rows
|
390
|
-
````
|
391
|
-
|
392
|
-
# Geo Filters
|
393
|
-
|
394
|
-
You can query Factual for entities located within a geographic area. For example:
|
395
|
-
|
396
|
-
````ruby
|
397
|
-
query = query.geo("$circle" => {"$center" => [34.06021, -118.41828], "$meters" => 5000})
|
398
|
-
````
|
399
|
-
|
400
|
-
# Facets
|
401
|
-
|
402
|
-
The driver fully supports Factual's Facets feature, which lets you return row counts for Factual tables, grouped by facets of data. For example, you may want to query all businesses within 1 mile of a location and for a count of those businesses by category.
|
403
|
-
|
404
|
-
For example:
|
405
|
-
|
406
|
-
````ruby
|
407
|
-
# Returns a count of Starbucks by country
|
408
|
-
factual.facets("global").select("country").search("starbucks").columns
|
409
|
-
````
|
410
|
-
|
411
|
-
## All Top Level Facets Parameters
|
412
|
-
|
413
|
-
<table>
|
414
|
-
<col width="33%"/>
|
415
|
-
<col width="33%"/>
|
416
|
-
<col width="33%"/>
|
417
|
-
<tr>
|
418
|
-
<th>Parameter</th>
|
419
|
-
<th>Description</th>
|
420
|
-
<th>Example</th>
|
421
|
-
</tr>
|
422
|
-
<tr>
|
423
|
-
<td>select</td>
|
424
|
-
<td>The fields for which facets should be generated. The response will not be ordered identically to this list, nor will it reflect any nested relationships between fields.</td>
|
425
|
-
<td><tt>.select("region", "locality")</tt></td>
|
426
|
-
</tr>
|
427
|
-
<tr>
|
428
|
-
<td>limit</td>
|
429
|
-
<td>The maximum number of unique facet values that can be returned for a single field. Range is 1-250. The default is 25.</td>
|
430
|
-
<td><tt>.limit(10)</tt></td>
|
431
|
-
</tr>
|
432
|
-
<tr>
|
433
|
-
<td>filters</td>
|
434
|
-
<td>Restrict the data returned to conform to specific conditions.</td>
|
435
|
-
<td><tt>.filters("name" => {"$bw" => "starbucks"})</tt></td>
|
436
|
-
</tr>
|
437
|
-
<tr>
|
438
|
-
<td>include_count</td>
|
439
|
-
<td>Include a count of the total number of rows in the dataset that conform to the request based on included filters. Requesting the row count will increase the time required to return a response. The default behavior is to NOT include a row count. When the row count is requested, the Response object will contain a valid total row count via <tt>.getTotalRowCount()</tt>.</td>
|
440
|
-
<td><tt>.include_count</tt></td>
|
441
|
-
</tr>
|
442
|
-
<tr>
|
443
|
-
<td>geo</td>
|
444
|
-
<td>Restrict data to be returned to be within a geographical range.</td>
|
445
|
-
<td>(See the section on Geo Filters)</td>
|
446
|
-
</tr>
|
447
|
-
<tr>
|
448
|
-
<td>search</td>
|
449
|
-
<td>Full text search query string.</td>
|
450
|
-
<td>
|
451
|
-
Find "sushi":<br><tt>.search("sushi")</tt><p>
|
452
|
-
Find "sushi" or "sashimi":<br><tt>.search("sushi, sashimi")</tt><p>
|
453
|
-
Find "sushi" and "santa" and "monica":<br><tt>.search("sushi santa monica")</tt>
|
454
|
-
</td>
|
455
|
-
</tr>
|
456
|
-
</table>
|
457
|
-
|
458
|
-
</table>
|
459
|
-
|
460
|
-
|
461
|
-
# Flag
|
462
|
-
|
463
|
-
Factual's Flag feature enables flagging problematic rows in Factual tables. Use this feature if you are requesting for an entity to be deleted or merged into a duplicate record.
|
464
|
-
|
465
|
-
## Simple Flag Example
|
466
|
-
|
467
|
-
````ruby
|
468
|
-
# User user123 flags row 0545b03f-9413-44ed-8882-3a9a461848da in the global dataset as inaccurate
|
469
|
-
factual.flag("global", "0545b03f-9413-44ed-8882-3a9a461848da", :inaccurate, "user123").write
|
470
|
-
````
|
471
|
-
|
472
|
-
The reason for flagging must be one of the following:
|
473
|
-
<ul>
|
474
|
-
<li>:duplicate
|
475
|
-
<li>:nonexistent
|
476
|
-
<li>:inaccurate
|
477
|
-
<li>:inappropriate
|
478
|
-
<li>:spam
|
479
|
-
<li>:other
|
480
|
-
</ul>
|
481
|
-
|
482
|
-
You can also create a Flag object and set it with optional parameters beforing writing it. For example:
|
483
|
-
|
484
|
-
````ruby
|
485
|
-
flag = factual.flag("global", "0545b03f-9413-44ed-8882-3a9a461848da", :inaccurate, "user123")
|
486
|
-
flag = flag.comment("this row is outdated").reference("http://www.example.com/somepage.html")
|
487
|
-
flag.write
|
488
|
-
````
|
489
|
-
|
490
|
-
## Optional Flag Parameters
|
491
|
-
|
492
|
-
<table>
|
493
|
-
<tr>
|
494
|
-
<th>Parameter</th>
|
495
|
-
<th>Description</th>
|
496
|
-
<th>Example</th>
|
497
|
-
</tr>
|
498
|
-
<tr>
|
499
|
-
<td>comment</td>
|
500
|
-
<td>Any english text comment that may help explain your corrections.</td>
|
501
|
-
<td><tt>.comment("this row is outdated")</tt></td>
|
502
|
-
</tr>
|
503
|
-
<tr>
|
504
|
-
<td>reference</td>
|
505
|
-
<td>A reference to a URL, title, person, etc. that is the source of this data.</td>
|
506
|
-
<td><tt>.reference("http://www.example.com/somepage.html")</tt></td>
|
507
|
-
</tr>
|
508
|
-
</table>
|
509
|
-
|
510
|
-
|
511
|
-
# Geopulse
|
512
|
-
|
513
|
-
The driver fully supports Factual's <a href="http://developer.factual.com/display/DOCS/Places+API+-+Geopulse">Geopulse</a> feature, which provides point-based access to geographic attributes: you provide a long/lat coordinate pair, we provide everything we can know about that geography.
|
514
|
-
|
515
|
-
The Geopulse API is made up of several "pulses". Pulses are georeferenced attributes generated by Factual, sourced from openly available content (such as the US Census), or provided to Factual by proprietary third-parties.
|
516
|
-
|
517
|
-
## Simple Geopulse Example
|
518
|
-
|
519
|
-
The <tt>geopulse</tt> method fetches results based on the given point:
|
520
|
-
|
521
|
-
````ruby
|
522
|
-
query = factual.geopulse(34.06021, -118.41828).select("commercial_density", "commercial_profile")
|
523
|
-
query.first
|
524
|
-
````
|
525
|
-
|
526
|
-
|
527
|
-
## All Top Level Geopulse Parameters
|
528
|
-
|
529
|
-
<table>
|
530
|
-
<tr>
|
531
|
-
<th>Parameter</th>
|
532
|
-
<th>Description</th>
|
533
|
-
<th>Example</th>
|
534
|
-
</tr>
|
535
|
-
<tr>
|
536
|
-
<td>geo</td>
|
537
|
-
<td>A geographic point around which information is retrieved.</td>
|
538
|
-
<td><tt>factual.geopulse(34.06021, -118.41828)</tt></td>
|
539
|
-
</tr>
|
540
|
-
<tr>
|
541
|
-
<td>select</td>
|
542
|
-
<td>What fields to include in the query results. Note that the order of fields will not necessarily be preserved in the resulting JSON response due to the nature of JSON hashes.</td>
|
543
|
-
<td><tt>.select("commercial_density", "commercial_profile")</tt></td>
|
544
|
-
</tr>
|
545
|
-
</table>
|
546
|
-
|
547
|
-
Available pulses include commercial_density, commercial_profile, income, race, hispanic, and age_by_gender.
|
548
|
-
|
549
|
-
You can see a full list of available Factual pulses and their possible return values, as well as full documentation, in [the Factual API docs for Geopulse](http://developer.factual.com/display/docs/Places+API+-+Geopulse).
|
550
|
-
|
551
|
-
|
552
|
-
# Reverse Geocoder
|
553
|
-
|
554
|
-
The driver fully supports Factual's <a href="http://developer.factual.com/display/DOCS/Places+API+-+Reverse+Geocoder">Reverse Geocoder</a> feature, which returns the nearest valid address given a longitude and latitude.
|
555
|
-
|
556
|
-
## Simple Reverse Geocoder Example
|
557
|
-
|
558
|
-
The <tt>geocode</tt> method fetches results based on the given point:
|
559
|
-
|
560
|
-
````ruby
|
561
|
-
query = factual.geocode(34.06021, -118.41828)
|
562
|
-
query.first
|
563
|
-
````
|
564
|
-
|
565
|
-
## All Top Level Reverse Geocoder Parameters
|
566
|
-
|
567
|
-
<table>
|
568
|
-
<tr>
|
569
|
-
<th>Parameter</th>
|
570
|
-
<th>Description</th>
|
571
|
-
<th>Example</th>
|
572
|
-
</tr>
|
573
|
-
<tr>
|
574
|
-
<td>geo</td>
|
575
|
-
<td>A valid geographic point for which the closest address is retrieved.</td>
|
576
|
-
<td><tt>factual.geocode(34.06021, -118.41828)</tt></td>
|
577
|
-
</tr>
|
578
|
-
</table>
|
579
|
-
|
580
|
-
|
581
|
-
# World Geographies
|
582
|
-
|
583
|
-
World Geographies contains administrative geographies (states, counties, countries), natural geographies (rivers, oceans, continents), and assorted geographic miscallaney. This resource is intended to complement Factual's Global Places and add utility to any geo-related content.
|
584
|
-
|
585
|
-
Common use cases include:
|
586
|
-
|
587
|
-
* Determining all cities within a state or all postal codes in a city
|
588
|
-
* Creating a type-ahead placename lookup
|
589
|
-
* Validating data against city, state, country and county names
|
590
|
-
* A translation table to convert between the search key used by a user, i.e. '慕尼黑' or 'Munich' for the native 'München'
|
591
|
-
|
592
|
-
You can use the <tt>query</tt> function to query World Geographies, supplying "world-geographies" as the table name.
|
593
|
-
|
594
|
-
Examples:
|
595
|
-
|
596
|
-
````ruby
|
597
|
-
# Get all towns surrounding Philadelphia
|
598
|
-
query = factual.table("world-geographies").select("neighbors").filters(:factual_id => "08ca0f62-8f76-11e1-848f-cfd5bf3ef515")
|
599
|
-
query.rows
|
600
|
-
````
|
601
|
-
|
602
|
-
````ruby
|
603
|
-
# Find the town zipcode 95008 belongs to
|
604
|
-
query = factual.table("world-geographies").filters(
|
605
|
-
{"$and" => [ {:name => "95008"},
|
606
|
-
{:country => "us"} ]} )
|
607
|
-
query.rows
|
608
|
-
````
|
609
|
-
|
610
|
-
````ruby
|
611
|
-
# Searching by placename, placetype, country and geographic hierarchy
|
612
|
-
query = factual.table("world-geographies").filters(
|
613
|
-
{"$and" => [ {:name => "wayne"},
|
614
|
-
{:country => "us"},
|
615
|
-
{:placetype => "locality"},
|
616
|
-
{:ancestors => {:"$search" => "08666f5c-8f76-11e1-848f-cfd5bf3ef515"}} ]} )
|
617
|
-
|
618
|
-
query.rows
|
619
|
-
````
|
620
|
-
|
621
|
-
For more details about World Geographies, including schema, see [the main API docs for World Geographies](http://developer.factual.com/display/docs/World+Geographies).
|
622
|
-
|
623
|
-
|
624
|
-
# Submit
|
625
|
-
|
626
|
-
The driver fully supports Factual's Submit feature, which enables you to submit edits to existing rows and/or submit new rows of data in Factual tables. For information on deleting records, see Flag.
|
627
|
-
|
628
|
-
|
629
|
-
## Simple Submit Examples
|
630
|
-
|
631
|
-
The <tt>submit</tt> method is a contribution to edit an existing row or add a new row:
|
632
|
-
|
633
|
-
````ruby
|
634
|
-
# Submit a new row to Factual's global dataset
|
635
|
-
factual.submit("global", "user123").values({"name" => "McDenny's", "address" => "1 Main St.", "locality" => "Bedrock", "region" => "BC"}).write
|
636
|
-
````
|
637
|
-
|
638
|
-
````ruby
|
639
|
-
# Submit a correction to an existing row in Factual's places dataset.
|
640
|
-
# Also set optional comment and reference
|
641
|
-
submit = factual.submit("places", "user123").values({:name => "McDenny's"})
|
642
|
-
submit = submit.comment("They changed their name last month").reference("http://www.example.com/mypage.html")
|
643
|
-
submit.write
|
644
|
-
````
|
645
|
-
|
646
|
-
|
647
|
-
## Required Submit Parameters
|
648
|
-
|
649
|
-
<table>
|
650
|
-
<tr>
|
651
|
-
<th>Parameter</th>
|
652
|
-
<th>Description</th>
|
653
|
-
<th>Example</th>
|
654
|
-
</tr>
|
655
|
-
<tr>
|
656
|
-
<td>values</td>
|
657
|
-
<td>A hash of names and values to be added to a Factual table</td>
|
658
|
-
<td><tt>{"name" => "McDenny's", "address" => "1 Main St.", "locality" => "Bedrock", "region" => "BC"}</tt></td>
|
659
|
-
</tr>
|
660
|
-
<tr>
|
661
|
-
<td>user</td>
|
662
|
-
<td>An arbitrary token representing the user contributing the data.</td>
|
663
|
-
<td><tt>user123</tt></td>
|
664
|
-
</tr>
|
665
|
-
</table>
|
666
|
-
|
667
|
-
## Optional Submit Parameters
|
668
|
-
|
669
|
-
<table>
|
670
|
-
<tr>
|
671
|
-
<th>Parameter</th>
|
672
|
-
<th>Description</th>
|
673
|
-
<th>Example</th>
|
674
|
-
</tr>
|
675
|
-
<tr>
|
676
|
-
<td>factual_id</td>
|
677
|
-
<td>The factual_id of the row to which you want to submit a correction</td>
|
678
|
-
<td><tt>.factual_id("0545b03f-9413-44ed-8882-3a9a461848da")</tt></td>
|
679
|
-
</tr>
|
680
|
-
<tr>
|
681
|
-
<td>comment</td>
|
682
|
-
<td>Any english text comment that may help explain your corrections.</td>
|
683
|
-
<td><tt>.comment("They changed their name last month")</tt></td>
|
684
|
-
</tr>
|
685
|
-
<tr>
|
686
|
-
<td>reference</td>
|
687
|
-
<td>A reference to a URL, title, person, etc. that is the source of this data.</td>
|
688
|
-
<td><tt>.reference("http://www.example.com/mypage.html")</tt></td>
|
689
|
-
</tr>
|
690
|
-
</table>
|
691
|
-
|
692
|
-
|
693
|
-
# Schema
|
694
|
-
|
695
|
-
You can query Factual for the detailed schema of any specific table in Factual. For example:
|
696
|
-
|
697
|
-
````ruby
|
698
|
-
# Returns a hash of metadata for the table named "global", including an array of fields
|
699
|
-
factual.table("global").schema
|
700
|
-
````
|
701
|
-
|
702
|
-
# Raw Read Queries
|
703
|
-
|
704
|
-
You can perform any read queries documented in the Factual API using the
|
705
|
-
raw read query. Just supply the full path (including the first
|
706
|
-
forward-slash) and the request will be made using your OAuth token:
|
707
|
-
|
708
|
-
````ruby
|
709
|
-
# Find rows in the restaurant database whose name begins with "Star" and return both the data and a total count of the matched rows
|
710
|
-
factual.read('/t/restaurants-us?filters={"name":{"$bw":"Star"}}&include_count=true')
|
711
|
-
````
|
712
|
-
|
713
|
-
# Monetize
|
714
|
-
|
715
|
-
The <a href="http://developer.factual.com/display/docs/Places+API+-+Monetize">Monetize API</a> enables you to find deals for places in Factual's Global Places database.
|
716
|
-
|
717
|
-
````ruby
|
718
|
-
query = @factual.monetize.search('sushi').filters(:place_postcode => 90067)
|
719
|
-
query.rows
|
720
|
-
````
|
721
|
-
|
722
|
-
# Multi
|
723
|
-
|
724
|
-
The <a href="http://developer.factual.com/display/docs/Core+API+-+Multi">multi API call</a> enables making multiple API GET requests on the same connection. Multi supports the read, crosswalk, resolve, facets, geocode and geopulse API calls.
|
725
|
-
|
726
|
-
````ruby
|
727
|
-
places_query = @factual.table("places").search('sushi').filters(:postcode => 90067)
|
728
|
-
geocode_query = @factual.geocode(34.06021,-118.41828)
|
729
|
-
|
730
|
-
responses = @factual.multi(
|
731
|
-
:nearby_sushi => places_query,
|
732
|
-
:factual_inc => geocode_query)
|
733
|
-
|
734
|
-
responses[:nearby_sushi].first
|
735
|
-
responses[:factual_inc].first
|
736
|
-
````
|
737
|
-
|
738
|
-
# Debug Mode
|
739
|
-
|
740
|
-
To see the query paths generated by the driver you can use it in debug mode by passing :debug => true as
|
741
|
-
the third argument of the Factual constructor. Here is an example in irb:
|
742
|
-
|
743
|
-
|
744
|
-
````ruby
|
745
|
-
> factual = Factual.new(key, secret, :debug => true)
|
746
|
-
> factual.table("places").filters("name" => {"$bw" => "starbucks"})
|
747
|
-
Request: http://api.v3.factual.com/t/places?filters=%7B%22name%22%3A%7B%22%24bw%22%3A%22starbucks%22%7D%7D
|
748
|
-
=> [{"address"=>"11290 Donner Pass Rd", "category"=>"Food & Beverage > Cafes, Coffee Houses & Tea Houses", ...
|
749
|
-
````
|
750
|
-
|
751
147
|
# Where to Get Help
|
752
148
|
|
753
149
|
If you think you've identified a specific bug in this driver, please file an issue in the github repo. Please be as specific as you can, including:
|
@@ -758,3 +154,6 @@ If you think you've identified a specific bug in this driver, please file an iss
|
|
758
154
|
* Detailed stack trace and/or line numbers
|
759
155
|
|
760
156
|
If you are having any other kind of issue, such as unexpected data or strange behaviour from Factual's API (or you're just not sure WHAT'S going on), please contact us through [GetSatisfaction](http://support.factual.com/factual).
|
157
|
+
|
158
|
+
# Ruby Driver Wiki
|
159
|
+
https://github.com/Factual/factual-ruby-driver/wiki
|
data/lib/factual.rb
CHANGED
@@ -2,6 +2,7 @@ require 'oauth'
|
|
2
2
|
require 'factual/api'
|
3
3
|
require 'factual/query/table'
|
4
4
|
require 'factual/query/facets'
|
5
|
+
require 'factual/query/match'
|
5
6
|
require 'factual/query/resolve'
|
6
7
|
require 'factual/query/crosswalk'
|
7
8
|
require 'factual/query/monetize'
|
@@ -28,9 +29,10 @@ class Factual
|
|
28
29
|
|
29
30
|
def crosswalk(namespace_id, namespace = nil)
|
30
31
|
if namespace
|
31
|
-
|
32
|
+
raise "DEPRECATED. For more information, please visit http://developer.factual.com/display/docs/Places+API+-+Crosswalk"
|
33
|
+
Query::Crosswalk.new(@api, :filters => {:namespace_id => namespace_id, :namespace => namespace})
|
32
34
|
else
|
33
|
-
Query::Crosswalk.new(@api, :factual_id => namespace_id)
|
35
|
+
Query::Crosswalk.new(@api, :filters => {:factual_id => namespace_id})
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
@@ -38,6 +40,10 @@ class Factual
|
|
38
40
|
Query::Monetize.new(@api)
|
39
41
|
end
|
40
42
|
|
43
|
+
def match(values)
|
44
|
+
Query::Match.new(@api, :values => values)
|
45
|
+
end
|
46
|
+
|
41
47
|
def resolve(values)
|
42
48
|
Query::Resolve.new(@api, :values => values)
|
43
49
|
end
|
@@ -50,8 +56,16 @@ class Factual
|
|
50
56
|
Query::Geopulse.new(@api, lat, lng)
|
51
57
|
end
|
52
58
|
|
53
|
-
def
|
54
|
-
@api.
|
59
|
+
def get(path, query={})
|
60
|
+
@api.raw_get(path, query)
|
61
|
+
end
|
62
|
+
|
63
|
+
def post(path, body={})
|
64
|
+
@api.raw_post(path, body)
|
65
|
+
end
|
66
|
+
|
67
|
+
def diffs(view, params = {})
|
68
|
+
@api.diffs(view, params)
|
55
69
|
end
|
56
70
|
|
57
71
|
def multi(queries)
|
data/lib/factual/api.rb
CHANGED
@@ -3,7 +3,7 @@ require 'cgi'
|
|
3
3
|
|
4
4
|
class Factual
|
5
5
|
class API
|
6
|
-
VERSION = "1.
|
6
|
+
VERSION = "1.3"
|
7
7
|
API_V3_HOST = "api.v3.factual.com"
|
8
8
|
DRIVER_VERSION_TAG = "factual-ruby-driver-v" + VERSION
|
9
9
|
PARAM_ALIASES = { :search => :q, :sort_asc => :sort }
|
@@ -29,11 +29,35 @@ class Factual
|
|
29
29
|
handle_request(:schema, query.path, query.params)["view"]
|
30
30
|
end
|
31
31
|
|
32
|
-
def
|
33
|
-
|
32
|
+
def raw_get(path, query)
|
33
|
+
path = '/' + path unless path =~ /^\//
|
34
|
+
url = "http://#{@host}#{path}?#{query_string(query)}"
|
35
|
+
resp = make_request(url)
|
36
|
+
payload = JSON.parse(resp.body)
|
34
37
|
handle_payload(payload)
|
35
38
|
end
|
36
39
|
|
40
|
+
def raw_post(path, body)
|
41
|
+
path = '/' + path unless path =~ /^\//
|
42
|
+
url = "http://#{@host}#{path}"
|
43
|
+
resp = make_request(url, query_string(body), :post)
|
44
|
+
payload = JSON.parse(resp.body)
|
45
|
+
handle_payload(payload)
|
46
|
+
end
|
47
|
+
|
48
|
+
def diffs(view_id, params = {})
|
49
|
+
start_date = (params[:start] || params["start"] || 0).to_i * 1000
|
50
|
+
end_date = (params[:end] || params["end"] || Time.now).to_i * 1000
|
51
|
+
|
52
|
+
path = "/t/#{view_id}/diffs?start=#{start_date}&end=#{end_date}"
|
53
|
+
url = "http://#{@host}#{path}"
|
54
|
+
resp = make_request(url)
|
55
|
+
|
56
|
+
resp.body.split("\n").collect do |rowJson|
|
57
|
+
row = JSON.parse(rowJson)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
37
61
|
def full_path(action, path, params)
|
38
62
|
fp = "/#{path}"
|
39
63
|
fp += "/#{action}" unless action == :read
|
@@ -4,12 +4,24 @@ class Factual
|
|
4
4
|
module Query
|
5
5
|
class Crosswalk < Base
|
6
6
|
def initialize(api, params = {})
|
7
|
-
@path = "
|
7
|
+
@path = "t/crosswalk"
|
8
8
|
@action = :read
|
9
9
|
super(api, params)
|
10
10
|
end
|
11
11
|
|
12
|
-
|
12
|
+
def only(*namespaces)
|
13
|
+
filters = @params[:filters] ? @params[:filters].dup : {}
|
14
|
+
|
15
|
+
if (namespaces.length == 1)
|
16
|
+
filters.merge!(:namespace => namespaces.first)
|
17
|
+
else
|
18
|
+
filters.merge!(:namespace => {"$in" => namespaces})
|
19
|
+
end
|
20
|
+
|
21
|
+
self.class.new(@api, @params.merge(:filters => filters))
|
22
|
+
end
|
23
|
+
|
24
|
+
[:limit, :include_count].each do |param|
|
13
25
|
define_method(param) do |*args|
|
14
26
|
self.class.new(@api, @params.merge(param => form_value(args)))
|
15
27
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'factual/query/base'
|
2
|
+
|
3
|
+
class Factual
|
4
|
+
module Query
|
5
|
+
class Match < Base
|
6
|
+
def initialize(api, params = {})
|
7
|
+
@path = "places/match"
|
8
|
+
@action = :read
|
9
|
+
super(api, params)
|
10
|
+
end
|
11
|
+
|
12
|
+
[:values].each do |param|
|
13
|
+
define_method(param) do |*args|
|
14
|
+
self.class.new(@api, @params.merge(param => form_value(args)))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
metadata
CHANGED
@@ -1,62 +1,73 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: factual-api
|
3
|
-
version: !ruby/object:Gem::Version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.3'
|
4
5
|
prerelease:
|
5
|
-
version: "1.2"
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- Rudiger Lippert
|
9
9
|
- Forrest Cao
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
- !ruby/object:Gem::Dependency
|
13
|
+
date: 2012-08-08 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
17
16
|
name: oauth
|
18
|
-
|
19
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
20
18
|
none: false
|
21
|
-
requirements:
|
22
|
-
- -
|
23
|
-
- !ruby/object:Gem::Version
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
24
22
|
version: 0.4.4
|
25
23
|
type: :runtime
|
26
|
-
version_requirements: *id001
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: json
|
29
24
|
prerelease: false
|
30
|
-
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: 0.4.4
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: json
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
31
34
|
none: false
|
32
|
-
requirements:
|
33
|
-
- -
|
34
|
-
- !ruby/object:Gem::Version
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
35
38
|
version: 1.2.0
|
36
39
|
type: :runtime
|
37
|
-
version_requirements: *id002
|
38
|
-
- !ruby/object:Gem::Dependency
|
39
|
-
name: rspec
|
40
40
|
prerelease: false
|
41
|
-
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
42
|
none: false
|
43
|
-
requirements:
|
44
|
-
- -
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version:
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 1.2.0
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
47
55
|
type: :development
|
48
|
-
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
49
63
|
description: Factual's official Ruby driver for the Factual public API.
|
50
|
-
email:
|
64
|
+
email:
|
51
65
|
- rudy@factual.com
|
52
66
|
- forrest@factual.com
|
53
67
|
executables: []
|
54
|
-
|
55
68
|
extensions: []
|
56
|
-
|
57
69
|
extra_rdoc_files: []
|
58
|
-
|
59
|
-
files:
|
70
|
+
files:
|
60
71
|
- lib/factual/api.rb
|
61
72
|
- lib/factual/multi.rb
|
62
73
|
- lib/factual/query/base.rb
|
@@ -64,6 +75,7 @@ files:
|
|
64
75
|
- lib/factual/query/facets.rb
|
65
76
|
- lib/factual/query/geocode.rb
|
66
77
|
- lib/factual/query/geopulse.rb
|
78
|
+
- lib/factual/query/match.rb
|
67
79
|
- lib/factual/query/monetize.rb
|
68
80
|
- lib/factual/query/resolve.rb
|
69
81
|
- lib/factual/query/table.rb
|
@@ -75,30 +87,26 @@ files:
|
|
75
87
|
- CHANGELOG.md
|
76
88
|
homepage: http://github.com/Factual/factual-ruby-driver
|
77
89
|
licenses: []
|
78
|
-
|
79
90
|
post_install_message:
|
80
91
|
rdoc_options: []
|
81
|
-
|
82
|
-
require_paths:
|
92
|
+
require_paths:
|
83
93
|
- lib
|
84
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
95
|
none: false
|
86
|
-
requirements:
|
87
|
-
- -
|
88
|
-
- !ruby/object:Gem::Version
|
96
|
+
requirements:
|
97
|
+
- - ! '>='
|
98
|
+
- !ruby/object:Gem::Version
|
89
99
|
version: 1.8.6
|
90
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
101
|
none: false
|
92
|
-
requirements:
|
93
|
-
- -
|
94
|
-
- !ruby/object:Gem::Version
|
102
|
+
requirements:
|
103
|
+
- - ! '>='
|
104
|
+
- !ruby/object:Gem::Version
|
95
105
|
version: 1.3.6
|
96
106
|
requirements: []
|
97
|
-
|
98
107
|
rubyforge_project:
|
99
108
|
rubygems_version: 1.8.24
|
100
109
|
signing_key:
|
101
110
|
specification_version: 3
|
102
111
|
summary: Ruby driver for Factual
|
103
112
|
test_files: []
|
104
|
-
|