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