| 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__ |