1 /** @file latlong_posting_source.cc
2 * @brief LatLongPostingSource implementation.
4 /* Copyright 2008 Lemur Consulting Ltd
5 * Copyright 2010,2011 Richard Boulton
6 * Copyright 2012,2015 Olly Betts
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
26 #include "xapian/geospatial.h"
28 #include "xapian/error.h"
29 #include "xapian/registry.h"
31 #include "net/length.h"
32 #include "serialise-double.h"
37 using namespace Xapian
;
41 weight_from_distance(double dist
, double k1
, double k2
)
43 return k1
* pow(dist
+ k1
, -k2
);
47 LatLongDistancePostingSource::calc_distance()
49 dist
= (*metric
)(centre
, get_value());
52 /// Validate the parameters supplied to LatLongDistancePostingSource.
54 validate_postingsource_params(double k1
, double k2
) {
56 string
msg("k1 parameter to LatLongDistancePostingSource must be "
57 "greater than 0; was ");
59 throw InvalidArgumentError(msg
);
62 string
msg("k2 parameter to LatLongDistancePostingSource must be "
63 "greater than 0; was ");
65 throw InvalidArgumentError(msg
);
69 LatLongDistancePostingSource::LatLongDistancePostingSource(
71 const LatLongCoords
& centre_
,
72 const LatLongMetric
* metric_
,
76 : ValuePostingSource(slot_
),
79 max_range(max_range_
),
83 validate_postingsource_params(k1
, k2
);
84 set_maxweight(weight_from_distance(0, k1
, k2
));
87 LatLongDistancePostingSource::LatLongDistancePostingSource(
89 const LatLongCoords
& centre_
,
90 const LatLongMetric
& metric_
,
94 : ValuePostingSource(slot_
),
96 metric(metric_
.clone()),
97 max_range(max_range_
),
101 validate_postingsource_params(k1
, k2
);
102 set_maxweight(weight_from_distance(0, k1
, k2
));
105 LatLongDistancePostingSource::LatLongDistancePostingSource(
107 const LatLongCoords
& centre_
,
111 : ValuePostingSource(slot_
),
113 metric(new Xapian::GreatCircleMetric()),
114 max_range(max_range_
),
118 validate_postingsource_params(k1
, k2
);
119 set_maxweight(weight_from_distance(0, k1
, k2
));
122 LatLongDistancePostingSource::~LatLongDistancePostingSource()
128 LatLongDistancePostingSource::next(double min_wt
)
130 ValuePostingSource::next(min_wt
);
132 while (!ValuePostingSource::at_end()) {
134 if (max_range
== 0 || dist
<= max_range
)
136 ValuePostingSource::next(min_wt
);
141 LatLongDistancePostingSource::skip_to(docid min_docid
,
144 ValuePostingSource::skip_to(min_docid
, min_wt
);
146 while (!ValuePostingSource::at_end()) {
148 if (max_range
== 0 || dist
<= max_range
)
150 ValuePostingSource::next(min_wt
);
155 LatLongDistancePostingSource::check(docid min_docid
,
158 if (!ValuePostingSource::check(min_docid
, min_wt
)) {
159 // check returned false, so we know the document is not in the source.
162 if (ValuePostingSource::at_end()) {
163 // return true, since we're definitely at the end of the list.
168 if (max_range
> 0 && dist
> max_range
) {
175 LatLongDistancePostingSource::get_weight() const
177 return weight_from_distance(dist
, k1
, k2
);
180 LatLongDistancePostingSource
*
181 LatLongDistancePostingSource::clone() const
183 return new LatLongDistancePostingSource(get_slot(), centre
,
189 LatLongDistancePostingSource::name() const
191 return "Xapian::LatLongDistancePostingSource";
195 LatLongDistancePostingSource::serialise() const
197 string serialised_centre
= centre
.serialise();
198 string metric_name
= metric
->name();
199 string serialised_metric
= metric
->serialise();
201 string result
= encode_length(get_slot());
202 result
+= encode_length(serialised_centre
.size());
203 result
+= serialised_centre
;
204 result
+= encode_length(metric_name
.size());
205 result
+= metric_name
;
206 result
+= encode_length(serialised_metric
.size());
207 result
+= serialised_metric
;
208 result
+= serialise_double(max_range
);
209 result
+= serialise_double(k1
);
210 result
+= serialise_double(k2
);
214 LatLongDistancePostingSource
*
215 LatLongDistancePostingSource::unserialise_with_registry(const string
&s
,
216 const Registry
& registry
) const
218 const char * p
= s
.data();
219 const char * end
= p
+ s
.size();
222 decode_length(&p
, end
, new_slot
);
224 decode_length_and_check(&p
, end
, len
);
225 string
new_serialised_centre(p
, len
);
227 decode_length_and_check(&p
, end
, len
);
228 string
new_metric_name(p
, len
);
230 decode_length_and_check(&p
, end
, len
);
231 string
new_serialised_metric(p
, len
);
233 double new_max_range
= unserialise_double(&p
, end
);
234 double new_k1
= unserialise_double(&p
, end
);
235 double new_k2
= unserialise_double(&p
, end
);
237 throw NetworkError("Bad serialised LatLongDistancePostingSource - junk at end");
240 LatLongCoords new_centre
;
241 new_centre
.unserialise(new_serialised_centre
);
243 const Xapian::LatLongMetric
* metric_type
=
244 registry
.get_lat_long_metric(new_metric_name
);
245 if (metric_type
== NULL
) {
246 string
msg("LatLongMetric ");
247 msg
+= new_metric_name
;
248 msg
+= " not registered";
249 throw InvalidArgumentError(msg
);
251 LatLongMetric
* new_metric
=
252 metric_type
->unserialise(new_serialised_metric
);
254 return new LatLongDistancePostingSource(new_slot
, new_centre
,
256 new_max_range
, new_k1
, new_k2
);
260 LatLongDistancePostingSource::init(const Database
& db_
)
262 ValuePostingSource::init(db_
);
263 if (max_range
> 0.0) {
264 // Possible that no documents are in range.
266 // Note - would be good to improve termfreq_est here, too, but
267 // I can't think of anything we can do with the information
273 LatLongDistancePostingSource::get_description() const
275 string
result("Xapian::LatLongDistancePostingSource(slot=");
276 result
+= str(get_slot());