line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Geo::Coder::Many; |
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
227431
|
use strict; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
72
|
|
4
|
2
|
|
|
2
|
|
11
|
use warnings; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
56
|
|
5
|
2
|
|
|
2
|
|
19
|
use Carp; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
177
|
|
6
|
2
|
|
|
2
|
|
2251
|
use List::MoreUtils qw(any); |
|
2
|
|
|
|
|
2802
|
|
|
2
|
|
|
|
|
174
|
|
7
|
2
|
|
|
2
|
|
2515
|
use Sort::Versions; |
|
2
|
|
|
|
|
1533
|
|
|
2
|
|
|
|
|
246
|
|
8
|
2
|
|
|
2
|
|
949
|
use Time::HiRes; |
|
2
|
|
|
|
|
1892
|
|
|
2
|
|
|
|
|
26
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our $VERSION = '0.46'; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# note - also update lists far below in pod |
13
|
2
|
|
|
2
|
|
1586
|
use Geo::Coder::Many::Bing; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
49
|
|
14
|
2
|
|
|
2
|
|
1147
|
use Geo::Coder::Many::Google; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
54
|
|
15
|
2
|
|
|
2
|
|
1463
|
use Geo::Coder::Many::Googlev3; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
46
|
|
16
|
2
|
|
|
2
|
|
1089
|
use Geo::Coder::Many::Mapquest; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
42
|
|
17
|
2
|
|
|
2
|
|
1112
|
use Geo::Coder::Many::OpenCage; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
45
|
|
18
|
2
|
|
|
2
|
|
1340
|
use Geo::Coder::Many::OSM; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
57
|
|
19
|
2
|
|
|
2
|
|
1505
|
use Geo::Coder::Many::Ovi; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
51
|
|
20
|
2
|
|
|
2
|
|
1516
|
use Geo::Coder::Many::PlaceFinder; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
62
|
|
21
|
|
|
|
|
|
|
|
22
|
2
|
|
|
|
|
147
|
use Geo::Coder::Many::Util qw( |
23
|
|
|
|
|
|
|
min_precision_filter |
24
|
|
|
|
|
|
|
max_precision_picker |
25
|
|
|
|
|
|
|
consensus_picker |
26
|
|
|
|
|
|
|
country_filter |
27
|
2
|
|
|
2
|
|
12
|
); |
|
2
|
|
|
|
|
4
|
|
28
|
|
|
|
|
|
|
|
29
|
2
|
|
|
2
|
|
1426
|
use Geo::Coder::Many::Scheduler::Selective; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
114
|
|
30
|
2
|
|
|
2
|
|
1527
|
use Geo::Coder::Many::Scheduler::OrderedList; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
100
|
|
31
|
2
|
|
|
2
|
|
1495
|
use Geo::Coder::Many::Scheduler::UniquenessScheduler::WRR; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
58
|
|
32
|
2
|
|
|
2
|
|
1314
|
use Geo::Coder::Many::Scheduler::UniquenessScheduler::WeightedRandom; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
5089
|
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
=head1 NAME |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
Geo::Coder::Many - Module to tie together multiple Geo::Coder::* modules |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head1 DESCRIPTION |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
Geo::Coder::Many provides a single interface to different remote |
41
|
|
|
|
|
|
|
(ie HTTP based) geocoding modules |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
Amongst other things, Geo::Coder::Many adds geocoder precision information, |
44
|
|
|
|
|
|
|
alternative scheduling methods (weighted random, and ordered list), timeouts |
45
|
|
|
|
|
|
|
for geocoders which are failing, and optional callbacks for result filtering |
46
|
|
|
|
|
|
|
and picking. |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=head1 SYNOPSIS |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
General steps for using Geo::Coder::Many: |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
=over |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=item 1. Create Geo::Coder::* objects for the geocoders you want to use, using |
55
|
|
|
|
|
|
|
their various individual setup procedures. |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=item 2. Create the Geo::Coder::Many object with C |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=item 3. Call C for each of the geocoders you want to use |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=item 4. Set any filter or picker callbacks you require (optional) |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=item 5. Use the C method to do all of your geocoding |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=back |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
=head1 EXAMPLE |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
Suppose the geocoders we want to use are called 'Locatorize' and 'WhereIzIt'. |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
use Geo::Coder::Locatorize; |
72
|
|
|
|
|
|
|
use Geo::Coder::WhereIzIt; |
73
|
|
|
|
|
|
|
use Geo::Coder::Many; |
74
|
|
|
|
|
|
|
use Geo::Coder::Many::Util qw( country_filter ); |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# Create the Geo::Coder::Many object, telling it to use a 'weighted random' |
77
|
|
|
|
|
|
|
# scheduling method |
78
|
|
|
|
|
|
|
my $options = { |
79
|
|
|
|
|
|
|
cache => $cache_object, |
80
|
|
|
|
|
|
|
scheduler_type => 'WRR', |
81
|
|
|
|
|
|
|
}; |
82
|
|
|
|
|
|
|
my $geocoder_many = Geo::Coder::Many->new( $options ); |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# Create and add a geocoder |
85
|
|
|
|
|
|
|
my $Locatorize = Geo::Coder::Locatorize->new( appid => 'mY_loCat0r1Ze_iD' ); |
86
|
|
|
|
|
|
|
my $Locatorize_options = { |
87
|
|
|
|
|
|
|
geocoder => $Locatorize, |
88
|
|
|
|
|
|
|
daily_limit => 2500, |
89
|
|
|
|
|
|
|
}; |
90
|
|
|
|
|
|
|
$geocoder_many->add_geocoder( $Locatorize_options ); |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
# Create and add a second geocoder |
93
|
|
|
|
|
|
|
my $WhereIzIt = Geo::Coder::WhereIzIt->new( apikey => 'mY_WhERiz1t_kEy' ); |
94
|
|
|
|
|
|
|
my $WhereIzIt_options = { |
95
|
|
|
|
|
|
|
geocoder => $WhereIzIt, |
96
|
|
|
|
|
|
|
daily_limit => 4000, |
97
|
|
|
|
|
|
|
}; |
98
|
|
|
|
|
|
|
$geocoder_many->add_geocoder( $WhereIzIt_options ); |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
# Use a filter callback from Geo::Coder::Many::Util |
101
|
|
|
|
|
|
|
$geocoder_many->set_filter_callback(country_filter('United Kingdom')); |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# Use a built-in picker callback |
104
|
|
|
|
|
|
|
$geocoder_many->set_picker_callback('max_precision'); |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
my $result = $geocoder_many->geocode( |
107
|
|
|
|
|
|
|
{ |
108
|
|
|
|
|
|
|
location => '82 Clerkenwell Road, London' |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
); |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
if (defined $result) { |
113
|
|
|
|
|
|
|
print "Country: ", $result->{country}, "\n"; |
114
|
|
|
|
|
|
|
print "Longitude: ", $result->{longitude}, "\n"; |
115
|
|
|
|
|
|
|
print "Latitude: ", $result->{latitude}, "\n"; |
116
|
|
|
|
|
|
|
print "Location: ", $result->{location}, "\n"; |
117
|
|
|
|
|
|
|
print "Response code: ", $result->{response_code}, "\n"; |
118
|
|
|
|
|
|
|
print "Address: ", $result->{address}, "\n"; |
119
|
|
|
|
|
|
|
print "Precision: ", $result->{precision}, "\n"; |
120
|
|
|
|
|
|
|
print "Geocoder: ", $result->{geocoder}, "\n"; |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
else { |
123
|
|
|
|
|
|
|
print "Failed to geocode!\n"; |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
=head1 METHODS |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=head2 new |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
Constructs a new Geo::Coder::Many object and returns it. Options should be |
131
|
|
|
|
|
|
|
provided as the entries of a hash reference, as follows: |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
KEY VALUE |
134
|
|
|
|
|
|
|
----------- -------------------- |
135
|
|
|
|
|
|
|
cache Cache object reference (optional) |
136
|
|
|
|
|
|
|
normalize_code_ref A normalization code ref (optional) |
137
|
|
|
|
|
|
|
scheduler_type Name of the scheduler type to use (default: WRR) |
138
|
|
|
|
|
|
|
use_timeouts Whether to time out failing geocoders (default: false) |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
If no C option is specified, no caching will be done for the geocoding |
141
|
|
|
|
|
|
|
results. |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
C is a code reference which is used to normalize location |
144
|
|
|
|
|
|
|
strings to ensure that all cache keys are normalized for correct lookup. |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
C specifies how load balancing should be done. |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
Scheduling schemes currently available are: |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=over |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=item WRR (Weighted round-robin) |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
Round-robin scheduling, weighted by the daily_limit values for the geocoders |
155
|
|
|
|
|
|
|
(The same behaviour as Geo::Coder::Multiple) |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=item OrderedList |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
A strict preferential ordering by daily_limit - the geocoder with the |
160
|
|
|
|
|
|
|
highest limit will always be used. If that fails, the next highest will be |
161
|
|
|
|
|
|
|
used, and so on. |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=item WeightedRandom |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
Geocoders will be picked at random, each with probability proportional to |
166
|
|
|
|
|
|
|
its specified daily_limit. |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=back |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
Other scheduling schemes can be implemented by sub-classing |
171
|
|
|
|
|
|
|
Geo::Coder::Many::Scheduler or Geo::Coder::Many::UniquenessScheduler. |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
If C is true, geocoders that are unsuccessful will not be queried |
174
|
|
|
|
|
|
|
again for a set amount of time. The timeout period will increase exponentially |
175
|
|
|
|
|
|
|
for every successive consecutive failure. |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
=cut |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
sub new { |
180
|
210
|
|
|
210
|
1
|
22689
|
my $class = shift; |
181
|
210
|
|
|
|
|
369
|
my $args = shift; |
182
|
|
|
|
|
|
|
|
183
|
210
|
|
|
|
|
1749
|
my $self = { |
184
|
|
|
|
|
|
|
cache => undef, |
185
|
|
|
|
|
|
|
geocoders => {}, |
186
|
|
|
|
|
|
|
scheduler => undef, |
187
|
|
|
|
|
|
|
normalize_code_ref => $args->{normalize_code_ref}, |
188
|
|
|
|
|
|
|
filter_callback => undef, |
189
|
|
|
|
|
|
|
picker_callback => undef, |
190
|
|
|
|
|
|
|
scheduler_type => $args->{scheduler_type}, |
191
|
|
|
|
|
|
|
use_timeouts => $args->{use_timeouts}, |
192
|
|
|
|
|
|
|
}; |
193
|
|
|
|
|
|
|
|
194
|
210
|
50
|
|
|
|
712
|
if ( !defined $args->{scheduler_type} ){ |
195
|
0
|
|
|
|
|
0
|
$self->{scheduler_type} = 'WRR'; |
196
|
|
|
|
|
|
|
} |
197
|
210
|
50
|
|
|
|
1958
|
if ( $self->{scheduler_type} !~ /OrderedList|WRR|WeightedRandom/x ) { |
198
|
0
|
|
|
|
|
0
|
carp "Unsupported scheduler type: should be OrderedList or WRR or |
199
|
|
|
|
|
|
|
WeightedRandom."; |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
|
202
|
210
|
|
|
|
|
884
|
bless $self, $class; |
203
|
|
|
|
|
|
|
|
204
|
210
|
50
|
|
|
|
556
|
if ( $args->{cache} ) { |
205
|
0
|
|
|
|
|
0
|
$self->_set_caching_object( $args->{cache} ); |
206
|
|
|
|
|
|
|
} |
207
|
210
|
|
|
|
|
544
|
return $self; |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
=head2 add_geocoder |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
This method adds a geocoder to the list of possibilities. |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
Before any geocoding can be performed, at least one geocoder must be added |
215
|
|
|
|
|
|
|
to the list of available geocoders. |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
If the same geocoder is added twice, only the instance added first will be |
218
|
|
|
|
|
|
|
used. All other additions will be ignored. |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
KEY VALUE |
221
|
|
|
|
|
|
|
----------- -------------------- |
222
|
|
|
|
|
|
|
geocoder geocoder object reference (required) |
223
|
|
|
|
|
|
|
daily_limit geocoder source limit per 24 hour period (required) |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
C should be a reference to a Geo::Coder::Something object, where |
226
|
|
|
|
|
|
|
'Something' is a supported geocoder type. For a geocoder to be supported, it |
227
|
|
|
|
|
|
|
needs to have a corresponding Geo::Coder::Many::Something adapter module. |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
Note that C is just treated as guideline for the chosen scheduler, |
230
|
|
|
|
|
|
|
and will not necessarily be strictly obeyed. |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
=cut |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
sub add_geocoder { |
235
|
420
|
|
|
420
|
1
|
3842
|
my ($self, $args) = @_; |
236
|
|
|
|
|
|
|
|
237
|
420
|
|
|
|
|
1007
|
my $module = ref $args->{geocoder}; |
238
|
420
|
|
|
|
|
1850
|
(my $plugin = $module) =~ s/Geo::Coder::/Geo::Coder::Many::/x; |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
# Check that the geocoder module is compatabible with our plugin. |
241
|
420
|
50
|
|
|
|
1253
|
if (!$self->_geocoder_module_is_compatible_with_plugin($module, $plugin)) { |
242
|
0
|
|
|
|
|
0
|
carp "Can't add $module due to version incompatibility"; |
243
|
0
|
|
|
|
|
0
|
return 0; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
420
|
|
|
|
|
573
|
eval { |
247
|
420
|
|
|
|
|
1876
|
my $geocoder = $plugin->new($args); |
248
|
420
|
50
|
|
|
|
3107
|
if (exists $self->{geocoders}->{$geocoder->get_name()}) { |
249
|
0
|
|
|
|
|
0
|
carp "Warning: duplicate geocoder (" . $geocoder->get_name() .")"; |
250
|
|
|
|
|
|
|
} |
251
|
420
|
|
|
|
|
25449
|
$self->{geocoders}->{$geocoder->get_name()} = $geocoder; |
252
|
|
|
|
|
|
|
}; |
253
|
|
|
|
|
|
|
|
254
|
420
|
50
|
|
|
|
22040
|
if ($@) { |
255
|
0
|
|
|
|
|
0
|
carp "Geocoder not supported - $module\n"; |
256
|
0
|
|
|
|
|
0
|
return 0; |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
|
259
|
420
|
|
|
|
|
1160
|
$self->_recalculate_geocoder_stats(); |
260
|
420
|
|
|
|
|
1135
|
return 1; |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
=head2 set_filter_callback |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
Sets the callback used for filtering results. By default, all results are |
266
|
|
|
|
|
|
|
passed through. If a callback is set, only results for which the callback |
267
|
|
|
|
|
|
|
returns true are passed through. The callback takes one argument: a Response |
268
|
|
|
|
|
|
|
object to be judged for fitness. It should return true or false, depending on |
269
|
|
|
|
|
|
|
whether that Response is deemed suitable for consideration by the picker. |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
=cut |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
sub set_filter_callback { |
274
|
210
|
|
|
210
|
1
|
1327
|
my ($self, $filter_callback) = @_; |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
# If given a scalar, look up the name |
277
|
210
|
100
|
|
|
|
744
|
if (ref($filter_callback) eq '') { |
278
|
60
|
|
|
|
|
438
|
my %callback_names = ( |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
# Accepting all results is the default behaviour |
281
|
|
|
|
|
|
|
qr/(all)?/x => undef, |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
); |
284
|
60
|
|
|
|
|
312
|
$filter_callback = $self->_lookup_callback( |
285
|
|
|
|
|
|
|
$filter_callback, |
286
|
|
|
|
|
|
|
\%callback_names |
287
|
|
|
|
|
|
|
); |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
# We should now have a code reference |
291
|
210
|
50
|
66
|
|
|
1253
|
if (defined $filter_callback && ref($filter_callback) ne 'CODE') { |
292
|
0
|
|
|
|
|
0
|
croak "set_filter_callback requires a scalar or a code reference\n"; |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
|
295
|
210
|
|
|
|
|
400
|
$self->{filter_callback} = $filter_callback; |
296
|
210
|
|
|
|
|
487
|
return; |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
=head2 set_picker_callback |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
Sets the callback used for result picking. This determines which single result |
302
|
|
|
|
|
|
|
will actually be returned by the geocode method. By default, the first valid |
303
|
|
|
|
|
|
|
result (that has passed the filter callback, if one was set) is returned. |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
As an alternative to passing a subroutine reference, you can pass a scalar with |
306
|
|
|
|
|
|
|
a name that refers to one of the built-in callbacks. An empty string or 'first' |
307
|
|
|
|
|
|
|
sets the behaviour back to the default: accept the first result that is |
308
|
|
|
|
|
|
|
offered. 'max_precision' fetches all results and chooses the one with the |
309
|
|
|
|
|
|
|
greatest precision value. |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
The picker callback has two arguments: a reference to an array of the valid |
312
|
|
|
|
|
|
|
results that have been collected so far, and a value that is true if there are |
313
|
|
|
|
|
|
|
more results available and false otherwise. The callback should return a single |
314
|
|
|
|
|
|
|
result from the list, if one is acceptable. If none are acceptable, the |
315
|
|
|
|
|
|
|
callback may return undef, indicating that more results to pick from are |
316
|
|
|
|
|
|
|
desired. If these are available, the picker will be called again once they have |
317
|
|
|
|
|
|
|
been added to the results array. |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
Note that since geocoders are not (currently) queried in parallel, a picker |
320
|
|
|
|
|
|
|
that requires lots of results to make a decision may take longer to return a |
321
|
|
|
|
|
|
|
value. |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
=cut |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
sub set_picker_callback { |
326
|
210
|
|
|
210
|
1
|
1016
|
my ($self, $picker_callback) = @_; |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
# If given a scalar, look up the name |
329
|
210
|
100
|
|
|
|
608
|
if (ref($picker_callback) eq '') { |
330
|
84
|
|
|
|
|
827
|
my %callback_names = ( |
331
|
|
|
|
|
|
|
qr/(first)?/x => undef, |
332
|
|
|
|
|
|
|
qr/max_precision/x => \&max_precision_picker, |
333
|
|
|
|
|
|
|
); |
334
|
84
|
|
|
|
|
412
|
$picker_callback = $self->_lookup_callback( |
335
|
|
|
|
|
|
|
$picker_callback, |
336
|
|
|
|
|
|
|
\%callback_names, |
337
|
|
|
|
|
|
|
); |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
# We should now have a code reference |
341
|
210
|
50
|
66
|
|
|
1401
|
if (defined $picker_callback && ref($picker_callback) ne 'CODE') { |
342
|
0
|
|
|
|
|
0
|
croak "set_picker_callback requires a scalar or a code reference\n"; |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
|
345
|
210
|
|
|
|
|
448
|
$self->{picker_callback} = $picker_callback; |
346
|
210
|
|
|
|
|
429
|
return; |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
=head2 geocode |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
my $options = { |
352
|
|
|
|
|
|
|
location => $location, |
353
|
|
|
|
|
|
|
results_cache => $cache, |
354
|
|
|
|
|
|
|
}; |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
my $found_location = $geocoder_many->geocode( $options ); |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
Arguments should be provided in a hash reference with the following entries: |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
KEY VALUE |
361
|
|
|
|
|
|
|
----------- -------------------- |
362
|
|
|
|
|
|
|
location location string to pass to geocoder |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
results_cache reference to a cache object; will override the default |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
no_cache if set, the result will not be retrieved or set in |
367
|
|
|
|
|
|
|
cache (off by default) |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
wait_for_retries if set, the method will wait until it's sure all |
370
|
|
|
|
|
|
|
geocoders have been tried (off by default) |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
This method is the basis for the class, it will retrieve result from cache |
373
|
|
|
|
|
|
|
first, and return if cache hit. |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
If the cache is missed, the C method is called, with the location as |
376
|
|
|
|
|
|
|
the argument, on the next available geocoder object in the sequence. |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
If called in an array context all the matching results will be returned, |
379
|
|
|
|
|
|
|
otherwise the first result will be returned. |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
A matching address will have the following keys in the hash reference. |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
KEY VALUE |
384
|
|
|
|
|
|
|
----------- -------------------- |
385
|
|
|
|
|
|
|
response_code integer response code (see below) |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
address matched address |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
latitude latitude of matched address |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
longitude longitude of matched address |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
country country of matched address (not available for all |
394
|
|
|
|
|
|
|
geocoders) |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
geocoder source used to lookup address |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
location the original query string |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
precision scalar ranging from 0.0 to 1.0, denoting the |
401
|
|
|
|
|
|
|
granularity of the result (undef if not known) |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
The C key will contain a string denoting which geocoder returned the |
404
|
|
|
|
|
|
|
results (eg, 'locatorize'). |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
The C key will contain the response code. The possible values |
407
|
|
|
|
|
|
|
are: |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
200 Success |
410
|
|
|
|
|
|
|
210 Success (from cache) |
411
|
|
|
|
|
|
|
401 Unable to find location |
412
|
|
|
|
|
|
|
402 All geocoder limits reached (not yet implemented) |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
C will return undef if none of the geocoders that were tried produced |
415
|
|
|
|
|
|
|
a result that satisfied the filter and picker callbacks. |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
=cut |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
sub geocode { |
420
|
2100
|
|
|
2100
|
1
|
157247
|
my ($self, $args) = @_; |
421
|
|
|
|
|
|
|
|
422
|
2100
|
50
|
|
|
|
4655
|
if ( !exists $args->{location} ) { |
423
|
0
|
|
|
|
|
0
|
croak "Geo::Coder::Many::geocode method requires a location!\n"; |
424
|
|
|
|
|
|
|
} |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
# If using cache, check that first |
427
|
2100
|
50
|
|
|
|
4581
|
if ( !$args->{no_cache} ){ |
428
|
2100
|
|
|
|
|
6479
|
my $response = $self->_get_from_cache( |
429
|
|
|
|
|
|
|
$args->{location}, |
430
|
|
|
|
|
|
|
$args->{cache}, |
431
|
|
|
|
|
|
|
); |
432
|
2100
|
50
|
|
|
|
5346
|
if ( defined $response ){ |
433
|
0
|
|
|
|
|
0
|
return $response |
434
|
|
|
|
|
|
|
} |
435
|
|
|
|
|
|
|
} |
436
|
|
|
|
|
|
|
|
437
|
2100
|
50
|
|
|
|
1978
|
if ( !keys %{$self->{geocoders}} ){ |
|
2100
|
|
|
|
|
5996
|
|
438
|
0
|
|
|
|
|
0
|
carp "Warning: geocode called, but no geocoders have been added!\n"; |
439
|
0
|
|
|
|
|
0
|
return; |
440
|
|
|
|
|
|
|
} |
441
|
|
|
|
|
|
|
|
442
|
2100
|
|
|
|
|
2875
|
my $previous_geocoder_name = ''; |
443
|
2100
|
|
|
|
|
3397
|
my $ra_valid_results = []; |
444
|
2100
|
|
|
|
|
2242
|
my $waiting_time = 0; |
445
|
2100
|
|
|
|
|
2240
|
my $accepted_response = undef; |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
# We have not yet tried any geocoders for this query - tell the scheduler. |
448
|
2100
|
|
|
|
|
30515
|
$self->{scheduler}->reset_available(); |
449
|
|
|
|
|
|
|
|
450
|
2100
|
|
|
|
|
4068
|
while ( !defined $accepted_response ) { |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
# Check whether we have geocoders to try |
453
|
|
|
|
|
|
|
# (next_available gives us the minimum length of time until there may |
454
|
|
|
|
|
|
|
# be a working geocoder, or undef if this is infinite) |
455
|
4176
|
|
|
|
|
68520
|
$waiting_time = $self->{scheduler}->next_available(); |
456
|
4176
|
100
|
|
|
|
9708
|
if (!defined $waiting_time) { |
457
|
|
|
|
|
|
|
# Run out of geocoders. |
458
|
572
|
|
|
|
|
1077
|
last; |
459
|
|
|
|
|
|
|
} |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
# If wait_for_retries is set, wait here until the time we were told |
462
|
3604
|
50
|
66
|
|
|
12387
|
if ( $waiting_time > 0 && $args->{ wait_for_retries } ) { |
463
|
0
|
|
|
|
|
0
|
Time::HiRes::sleep($waiting_time); |
464
|
|
|
|
|
|
|
} |
465
|
|
|
|
|
|
|
|
466
|
3604
|
|
|
|
|
7014
|
my $geocoder = $self->_get_next_geocoder(); |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
# No more geocoders? We'll return undef later |
469
|
3604
|
100
|
|
|
|
7929
|
last if (!defined $geocoder); |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
# Check the geocoder has an OK name |
472
|
2411
|
|
|
|
|
11211
|
my $geocoder_name = $geocoder->get_name(); |
473
|
|
|
|
|
|
|
|
474
|
2411
|
50
|
|
|
|
137592
|
if ( $geocoder_name eq $previous_geocoder_name ) { |
475
|
0
|
|
|
|
|
0
|
carp "The scheduler is bad - it returned two geocoders with the " |
476
|
|
|
|
|
|
|
."same name, between calls to reset_available!"; |
477
|
|
|
|
|
|
|
} |
478
|
2411
|
50
|
|
0
|
|
7385
|
next if ( any { $geocoder_name eq $_ } @{$args->{geocoders_to_skip} || []} ); |
|
0
|
50
|
|
|
|
0
|
|
|
2411
|
|
|
|
|
14033
|
|
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
# Use the current geocoder to geocode the requested location |
481
|
2411
|
|
|
|
|
14744
|
my $Response = $geocoder->geocode( $args->{location} ); |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
# Tell the scheduler about how successful the geocoder was |
484
|
2411
|
50
|
|
|
|
16763
|
if (defined $Response) { |
485
|
|
|
|
|
|
|
|
486
|
2411
|
|
|
|
|
6837
|
my $feedback = { |
487
|
|
|
|
|
|
|
response_code => $Response->get_response_code(), |
488
|
|
|
|
|
|
|
}; |
489
|
2411
|
|
|
|
|
9638
|
$self->{scheduler}->process_feedback($geocoder_name, $feedback); |
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
else { |
492
|
0
|
|
|
|
|
0
|
carp "Geocoder $geocoder_name returned undef."; |
493
|
|
|
|
|
|
|
} |
494
|
|
|
|
|
|
|
|
495
|
2411
|
|
|
|
|
2915
|
$previous_geocoder_name = $geocoder_name; |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
# If our response has a valid code |
498
|
2411
|
100
|
|
|
|
4761
|
if ( $self->_response_valid($Response) ) { |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
# Apply the filter callback to the response entries |
501
|
1205
|
|
|
|
|
2361
|
my @passed_responses = grep { |
502
|
1205
|
|
|
|
|
52791
|
$self->_passes_filter($_) |
503
|
|
|
|
|
|
|
} $Response->get_responses(); |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
# If none passed, this whole response is no good. |
506
|
1205
|
100
|
|
|
|
4907
|
if (@passed_responses == 0) { |
507
|
269
|
|
|
|
|
1711
|
next; |
508
|
|
|
|
|
|
|
} |
509
|
|
|
|
|
|
|
|
510
|
936
|
100
|
|
|
|
1825
|
if ( defined ($self->{picker_callback}) ) { |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
# Add any results that pass the filter to the array of valid |
513
|
|
|
|
|
|
|
# results to be picked from |
514
|
773
|
|
|
|
|
1468
|
for my $result (@passed_responses) { |
515
|
773
|
|
|
|
|
1874
|
unshift ( |
516
|
|
|
|
|
|
|
@$ra_valid_results, |
517
|
|
|
|
|
|
|
$self->_form_response( $result, $Response ) |
518
|
|
|
|
|
|
|
); |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
# See whether this is good enough for the picker |
522
|
773
|
|
|
|
|
1417
|
my $pc = $self->{picker_callback}; |
523
|
|
|
|
|
|
|
|
524
|
773
|
|
|
|
|
2538
|
my $more_available = |
525
|
|
|
|
|
|
|
defined $self->{scheduler}->next_available(); |
526
|
|
|
|
|
|
|
|
527
|
773
|
|
|
|
|
2171
|
my $picked = $pc->( $ra_valid_results, $more_available ); |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
# Found an agreeable response! Use that. |
530
|
773
|
100
|
|
|
|
6698
|
if (defined $picked) { |
531
|
172
|
|
|
|
|
1044
|
$accepted_response = $picked; |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
} |
534
|
|
|
|
|
|
|
else { |
535
|
|
|
|
|
|
|
# No picker? Just accept the first valid response. |
536
|
163
|
|
|
|
|
344
|
$accepted_response = $self->_form_response( |
537
|
|
|
|
|
|
|
$passed_responses[0], |
538
|
|
|
|
|
|
|
$Response |
539
|
|
|
|
|
|
|
); |
540
|
|
|
|
|
|
|
} |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
} |
543
|
|
|
|
|
|
|
}; |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
# Definitely run out of geocoders - let's give the picker one last chance, |
546
|
|
|
|
|
|
|
# just in case. |
547
|
2100
|
100
|
100
|
|
|
8876
|
if (defined ($self->{picker_callback}) && !defined $accepted_response ) { |
548
|
1508
|
|
|
|
|
4919
|
$accepted_response = $self->{picker_callback}->( $ra_valid_results, 0 ); |
549
|
|
|
|
|
|
|
} |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
# If we're using a cache and we have a good response, let's cache it. |
552
|
2100
|
50
|
|
|
|
8209
|
if ( !$args->{no_cache} ) { |
553
|
2100
|
|
|
|
|
14259
|
$self->_set_in_cache( |
554
|
|
|
|
|
|
|
$args->{location}, |
555
|
|
|
|
|
|
|
$accepted_response, |
556
|
|
|
|
|
|
|
$args->{cache} |
557
|
|
|
|
|
|
|
); |
558
|
|
|
|
|
|
|
} |
559
|
|
|
|
|
|
|
|
560
|
2100
|
|
|
|
|
9875
|
return $accepted_response; |
561
|
|
|
|
|
|
|
} |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
=head2 get_geocoders |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
Returns a reference to a list of the geocoders that have been added to |
566
|
|
|
|
|
|
|
the Many instance |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
=cut |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
sub get_geocoders { |
571
|
420
|
|
|
420
|
1
|
6318
|
my $self = shift; |
572
|
|
|
|
|
|
|
|
573
|
420
|
|
|
|
|
590
|
my $ra_geocoders = []; |
574
|
420
|
|
|
|
|
518
|
foreach my $key ( sort keys %{$self->{geocoders}} ) { |
|
420
|
|
|
|
|
2535
|
|
575
|
630
|
|
|
|
|
692
|
push @{$ra_geocoders}, $self->{geocoders}->{$key}; |
|
630
|
|
|
|
|
1794
|
|
576
|
|
|
|
|
|
|
} |
577
|
420
|
|
|
|
|
955
|
return $ra_geocoders; |
578
|
|
|
|
|
|
|
} |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
### INTERNAL METHODS |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
# _geocoder_module_is_compatible_with_plugin |
584
|
|
|
|
|
|
|
# |
585
|
|
|
|
|
|
|
# Check that the installed Geo::Coder module is compatible |
586
|
|
|
|
|
|
|
# with the Geo::Coder::Many plugin, based on a minimum version |
587
|
|
|
|
|
|
|
sub _geocoder_module_is_compatible_with_plugin { |
588
|
420
|
|
|
420
|
|
764
|
my ($self, $module, $plugin) = @_; |
589
|
|
|
|
|
|
|
|
590
|
420
|
50
|
|
|
|
3774
|
if ($plugin->can("_MIN_MODULE_VERSION")) { |
591
|
0
|
|
|
|
|
0
|
my ($have_version, $min_version) = ( |
592
|
|
|
|
|
|
|
$module->VERSION, |
593
|
|
|
|
|
|
|
$plugin->_MIN_MODULE_VERSION, |
594
|
|
|
|
|
|
|
); |
595
|
|
|
|
|
|
|
|
596
|
0
|
0
|
|
|
|
0
|
if (versioncmp($have_version, $min_version) < 0) { |
597
|
0
|
|
|
|
|
0
|
carp "$plugin requires $module $min_version or above"; |
598
|
0
|
|
|
|
|
0
|
return 0; |
599
|
|
|
|
|
|
|
} |
600
|
|
|
|
|
|
|
} |
601
|
|
|
|
|
|
|
|
602
|
420
|
|
|
|
|
1312
|
return 1; |
603
|
|
|
|
|
|
|
} |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
# _form_response |
607
|
|
|
|
|
|
|
# |
608
|
|
|
|
|
|
|
# Takes a result hash and a Response object and mashes them into a single flat |
609
|
|
|
|
|
|
|
# hash, allowing results from different geocoders to be more easily assimilated |
610
|
|
|
|
|
|
|
# |
611
|
|
|
|
|
|
|
sub _form_response { |
612
|
936
|
|
|
936
|
|
1584
|
my ($self, $rh_result, $response) = @_; |
613
|
936
|
|
|
|
|
1949
|
$rh_result->{location} = $response->{location}; |
614
|
936
|
|
|
|
|
1714
|
$rh_result->{geocoder} = $response->{geocoder}; |
615
|
936
|
|
|
|
|
2557
|
$rh_result->{response_code} = $response->{response_code}; |
616
|
936
|
|
|
|
|
3877
|
return $rh_result; |
617
|
|
|
|
|
|
|
} |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
# _lookup_callback |
620
|
|
|
|
|
|
|
# |
621
|
|
|
|
|
|
|
# Given a name and a list of mappings from names to code references, do a fuzzy |
622
|
|
|
|
|
|
|
# lookup of the name and return the appropriate subroutine. |
623
|
|
|
|
|
|
|
# |
624
|
|
|
|
|
|
|
sub _lookup_callback { |
625
|
144
|
|
|
144
|
|
304
|
my ($self, $name, $rh_callbacks) = @_; |
626
|
|
|
|
|
|
|
|
627
|
144
|
50
|
|
|
|
376
|
ref($name) eq '' |
628
|
|
|
|
|
|
|
or croak( "Trying to look up something which isn't a name!\n" ); |
629
|
|
|
|
|
|
|
|
630
|
144
|
|
|
|
|
182
|
while (my ($name_regex, $callback) = each %{$rh_callbacks}) { |
|
187
|
|
|
|
|
710
|
|
631
|
187
|
|
|
|
|
3669
|
my $regex = qr/^\s*$name_regex\s*$/msx; |
632
|
|
|
|
|
|
|
|
633
|
187
|
100
|
|
|
|
1658
|
if ($name =~ $regex) { |
634
|
144
|
|
|
|
|
544
|
return $callback; |
635
|
|
|
|
|
|
|
} |
636
|
|
|
|
|
|
|
} |
637
|
|
|
|
|
|
|
|
638
|
0
|
|
|
|
|
0
|
carp( "\'$name\' is not a built-in callback.\n" ); |
639
|
0
|
|
|
|
|
0
|
return; |
640
|
|
|
|
|
|
|
} |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
# _response_valid |
643
|
|
|
|
|
|
|
# |
644
|
|
|
|
|
|
|
# Checks that a response is defined and has a valid response code, |
645
|
|
|
|
|
|
|
# |
646
|
|
|
|
|
|
|
sub _response_valid { |
647
|
2411
|
|
|
2411
|
|
3122
|
my $self = shift; |
648
|
2411
|
|
|
|
|
2601
|
my $response = shift; |
649
|
2411
|
50
|
|
|
|
5009
|
if ( !defined($response) ) { |
650
|
0
|
|
|
|
|
0
|
return 0; |
651
|
|
|
|
|
|
|
} |
652
|
2411
|
|
|
|
|
6177
|
return HTTP::Response->new( $response->get_response_code )->is_success; |
653
|
|
|
|
|
|
|
} |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
# _passes_filter |
656
|
|
|
|
|
|
|
# |
657
|
|
|
|
|
|
|
# Check a response passes the filter callback (if one is set). |
658
|
|
|
|
|
|
|
# |
659
|
|
|
|
|
|
|
sub _passes_filter { |
660
|
1205
|
|
|
1205
|
|
1643
|
my ($self, $response) = @_; |
661
|
1205
|
100
|
|
|
|
2804
|
if ( !defined $self->{filter_callback} ) { |
662
|
332
|
|
|
|
|
970
|
return 1; |
663
|
|
|
|
|
|
|
} |
664
|
873
|
|
|
|
|
2657
|
return $self->{filter_callback}->( $response ); |
665
|
|
|
|
|
|
|
} |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
# _get_next_geocoder |
668
|
|
|
|
|
|
|
# |
669
|
|
|
|
|
|
|
# Requests the next geocoder from the scheduler and looks it up in the geocoders |
670
|
|
|
|
|
|
|
# hash. |
671
|
|
|
|
|
|
|
# |
672
|
|
|
|
|
|
|
sub _get_next_geocoder { |
673
|
3604
|
|
|
3604
|
|
3966
|
my $self = shift; |
674
|
|
|
|
|
|
|
|
675
|
3604
|
|
|
|
|
10247
|
my $next = $self->{scheduler}->get_next_unique(); |
676
|
3604
|
100
|
66
|
|
|
14735
|
return if ( (!defined $next) || $next eq ''); |
677
|
|
|
|
|
|
|
|
678
|
2411
|
|
|
|
|
5677
|
return $self->{geocoders}{$next}; |
679
|
|
|
|
|
|
|
} |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
# _recalculate_geocoder_stats |
682
|
|
|
|
|
|
|
# |
683
|
|
|
|
|
|
|
# Assigns weights to the current geocoders, and initialises the scheduler as |
684
|
|
|
|
|
|
|
# appropriate. |
685
|
|
|
|
|
|
|
# |
686
|
|
|
|
|
|
|
sub _recalculate_geocoder_stats { |
687
|
420
|
|
|
420
|
|
574
|
my $self = shift; |
688
|
|
|
|
|
|
|
|
689
|
420
|
|
|
|
|
887
|
my $ra_geocoders = $self->get_geocoders(); |
690
|
420
|
|
|
|
|
739
|
my $ra_slim_geocoders = []; |
691
|
|
|
|
|
|
|
|
692
|
420
|
|
|
|
|
546
|
foreach my $geocoder ( @{$ra_geocoders} ) { |
|
420
|
|
|
|
|
792
|
|
693
|
|
|
|
|
|
|
|
694
|
630
|
|
50
|
|
|
3046
|
my $tmp = { |
695
|
|
|
|
|
|
|
weight => $geocoder->get_daily_limit() || 1, |
696
|
|
|
|
|
|
|
name => $geocoder->get_name(), |
697
|
|
|
|
|
|
|
}; |
698
|
630
|
|
|
|
|
66383
|
push @{$ra_slim_geocoders}, $tmp; |
|
630
|
|
|
|
|
1789
|
|
699
|
|
|
|
|
|
|
} |
700
|
420
|
|
|
|
|
1505
|
$self->{scheduler} = $self->_new_scheduler($ra_slim_geocoders); |
701
|
420
|
|
|
|
|
3307
|
return; |
702
|
|
|
|
|
|
|
} |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
# _new_scheduler |
705
|
|
|
|
|
|
|
# |
706
|
|
|
|
|
|
|
# Returns an instance of the currently-set scheduler, with the specified |
707
|
|
|
|
|
|
|
# geocoders. |
708
|
|
|
|
|
|
|
# |
709
|
|
|
|
|
|
|
sub _new_scheduler { |
710
|
420
|
|
|
420
|
|
629
|
my $self = shift; |
711
|
420
|
|
|
|
|
511
|
my $geocoders = shift; |
712
|
|
|
|
|
|
|
|
713
|
420
|
|
|
|
|
651
|
my $base_scheduler_name = "Geo::Coder::Many::Scheduler::"; |
714
|
420
|
100
|
|
|
|
1886
|
if ($self->{scheduler_type} =~ m/^(WRR|WeightedRandom)$/msx) { |
715
|
280
|
|
|
|
|
471
|
$base_scheduler_name .= "UniquenessScheduler::"; |
716
|
|
|
|
|
|
|
} |
717
|
420
|
|
|
|
|
675
|
$base_scheduler_name .= $self->{scheduler_type}; |
718
|
420
|
100
|
|
|
|
966
|
if ($self->{use_timeouts}) { |
719
|
210
|
|
|
|
|
1015
|
return Geo::Coder::Many::Scheduler::Selective->new( |
720
|
|
|
|
|
|
|
$geocoders, |
721
|
|
|
|
|
|
|
$base_scheduler_name |
722
|
|
|
|
|
|
|
); |
723
|
|
|
|
|
|
|
} |
724
|
210
|
|
|
|
|
1015
|
return $base_scheduler_name->new($geocoders); |
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
# _set_caching_object |
728
|
|
|
|
|
|
|
# |
729
|
|
|
|
|
|
|
# Set the list of cache objects |
730
|
|
|
|
|
|
|
# |
731
|
|
|
|
|
|
|
sub _set_caching_object { |
732
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
733
|
0
|
|
|
|
|
0
|
my $cache_obj = shift; |
734
|
|
|
|
|
|
|
|
735
|
0
|
|
|
|
|
0
|
$self->_test_cache_object( $cache_obj ); |
736
|
0
|
|
|
|
|
0
|
$self->{cache} = $cache_obj; |
737
|
0
|
|
|
|
|
0
|
$self->{cache_enabled} = 1; |
738
|
0
|
|
|
|
|
0
|
return; |
739
|
|
|
|
|
|
|
} |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
# _test_cache_object |
742
|
|
|
|
|
|
|
# |
743
|
|
|
|
|
|
|
# Test the cache to ensure it has 'get', 'set' and 'remove' methods |
744
|
|
|
|
|
|
|
# |
745
|
|
|
|
|
|
|
sub _test_cache_object { |
746
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
747
|
0
|
|
|
|
|
0
|
my $cache_object = shift; |
748
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
# Test to ensure the cache works |
750
|
|
|
|
|
|
|
{ |
751
|
0
|
|
|
|
|
0
|
my $result = eval { |
|
0
|
|
|
|
|
0
|
|
752
|
0
|
|
|
|
|
0
|
$cache_object->set( '1234', 'test' ); |
753
|
0
|
0
|
|
|
|
0
|
croak unless( $cache_object->get('1234') eq 'test' ); |
754
|
0
|
|
|
|
|
0
|
1; |
755
|
|
|
|
|
|
|
}; |
756
|
0
|
0
|
0
|
|
|
0
|
if ( (!$result) || $@ ) { |
757
|
0
|
|
|
|
|
0
|
croak "Unable to use user provided cache object: ". ref($cache_object); |
758
|
|
|
|
|
|
|
} |
759
|
|
|
|
|
|
|
} |
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
# Test to ensure the cache supports references |
762
|
|
|
|
|
|
|
{ |
763
|
0
|
|
|
|
|
0
|
my $result = eval { |
|
0
|
|
|
|
|
0
|
|
764
|
0
|
|
|
|
|
0
|
$cache_object->set( 'abc', { a => 1, b => 2, c => 3 }); |
765
|
0
|
0
|
|
|
|
0
|
croak unless ( $cache_object->get('abc')->{'b'} == 2 ); |
766
|
0
|
|
|
|
|
0
|
1; |
767
|
|
|
|
|
|
|
}; |
768
|
0
|
0
|
0
|
|
|
0
|
if ( (!$result) || $@ ) { |
769
|
0
|
|
|
|
|
0
|
croak "Unable to use user provided cache object " |
770
|
|
|
|
|
|
|
. "(references not stored safely): ", ref($cache_object); |
771
|
|
|
|
|
|
|
} |
772
|
|
|
|
|
|
|
} |
773
|
|
|
|
|
|
|
|
774
|
0
|
|
|
|
|
0
|
return; |
775
|
|
|
|
|
|
|
} |
776
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
# _set_in_cache |
778
|
|
|
|
|
|
|
# |
779
|
|
|
|
|
|
|
# Store the result in the cache |
780
|
|
|
|
|
|
|
# |
781
|
|
|
|
|
|
|
sub _set_in_cache { |
782
|
2100
|
|
|
2100
|
|
3084
|
my $self = shift; |
783
|
2100
|
|
|
|
|
2837
|
my $location = shift; |
784
|
2100
|
|
|
|
|
2417
|
my $Response = shift; |
785
|
2100
|
|
33
|
|
|
9916
|
my $cache = shift || $self->{cache}; |
786
|
|
|
|
|
|
|
|
787
|
2100
|
50
|
33
|
|
|
7952
|
if ($location && $cache){ |
788
|
0
|
|
0
|
|
|
0
|
my $key = $self->_normalize_cache_key( $location ) || $location; |
789
|
0
|
|
|
|
|
0
|
$cache->set( $key, $Response ); |
790
|
0
|
|
|
|
|
0
|
return 1; |
791
|
|
|
|
|
|
|
} |
792
|
2100
|
|
|
|
|
3288
|
return 0; |
793
|
|
|
|
|
|
|
} |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
# _get_from_cache |
796
|
|
|
|
|
|
|
# |
797
|
|
|
|
|
|
|
# Check the cache to see if the data is available |
798
|
|
|
|
|
|
|
# |
799
|
|
|
|
|
|
|
sub _get_from_cache { |
800
|
2100
|
|
|
2100
|
|
2341
|
my $self = shift; |
801
|
2100
|
|
|
|
|
2640
|
my $location = shift; |
802
|
2100
|
|
33
|
|
|
8983
|
my $cache = shift || $self->{cache}; |
803
|
|
|
|
|
|
|
|
804
|
2100
|
50
|
33
|
|
|
4925
|
if ( $cache && $location ) { |
805
|
0
|
|
0
|
|
|
0
|
my $key = $self->_normalize_cache_key($location) || $location; |
806
|
0
|
|
|
|
|
0
|
my $Response = $cache->get( $key ); |
807
|
0
|
0
|
|
|
|
0
|
if ( $Response ) { |
808
|
0
|
|
|
|
|
0
|
$Response->{response_code} = 210; |
809
|
0
|
|
|
|
|
0
|
return $Response; |
810
|
|
|
|
|
|
|
} |
811
|
|
|
|
|
|
|
} |
812
|
2100
|
|
|
|
|
3514
|
return; |
813
|
|
|
|
|
|
|
} |
814
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
# _normalize_cache_key |
816
|
|
|
|
|
|
|
# |
817
|
|
|
|
|
|
|
# Use the provided normalize_code_ref callback (if one is set) to return a |
818
|
|
|
|
|
|
|
# normalized string to use as a cache key. |
819
|
|
|
|
|
|
|
# |
820
|
|
|
|
|
|
|
sub _normalize_cache_key { |
821
|
0
|
|
|
0
|
|
|
my $self = shift; |
822
|
0
|
|
|
|
|
|
my $location = shift; |
823
|
|
|
|
|
|
|
|
824
|
0
|
0
|
|
|
|
|
if ( $self->{normalize_code_ref} ) { |
825
|
0
|
|
|
|
|
|
my $code_ref = $self->{normalize_code_ref}; |
826
|
0
|
|
|
|
|
|
return $code_ref->( $location ); |
827
|
|
|
|
|
|
|
} |
828
|
0
|
|
|
|
|
|
return $location; |
829
|
|
|
|
|
|
|
} |
830
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
1; |
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
__END__ |