Пример #1
0
	def get_nearest(self, query_data, range=_INFINITY, limit=_INFINITY):
		"""
		Returns an iterator on the indexed data nearest to the query_data. The
		returned items are tuples containing the data and its distance to the
		query_data, in increasing distance order. The results can be limited by
		the range (maximum distance from the query_data) and limit arguments.
		"""
		if self.root is None:
			# No indexed data!
			return
		
		distance = self.distance_function(query_data, self.root.data)
		min_distance = max(distance - self.root.radius, 0)
		
		pending_queue = HeapQueue(
				content=[_ItemWithDistances(item=self.root, distance=distance, min_distance=min_distance)],
				key=lambda iwd: iwd.min_distance,
			)
		
		nearest_queue = HeapQueue(key=lambda iwd: iwd.distance)
		
		yielded_count = 0
		
		while pending_queue:
			pending = pending_queue.pop()
			
			node = pending.item
			assert isinstance(node, _Node)
			
			for child in node.children.itervalues():
				if abs(pending.distance - child.distance_to_parent) - child.radius <= range:
					child_distance = self.distance_function(query_data, child.data)
					child_min_distance = max(child_distance - child.radius, 0)
					if child_min_distance <= range:
						iwd = _ItemWithDistances(item=child, distance=child_distance, min_distance=child_min_distance)
						if isinstance(child, _Entry):
							nearest_queue.push(iwd)
						else:
							pending_queue.push(iwd)
			
			# Tries to yield known results so far
			if pending_queue:
				next_pending = pending_queue.head()
				next_pending_min_distance = next_pending.min_distance
			else:
				next_pending_min_distance = _INFINITY
			
			while nearest_queue:
				next_nearest = nearest_queue.head()
				assert isinstance(next_nearest, _ItemWithDistances)
				if next_nearest.distance <= next_pending_min_distance:
					_ = nearest_queue.pop()
					assert _ is next_nearest
					
					yield self.ResultItem(data=next_nearest.item.data, distance=next_nearest.distance)
					yielded_count += 1
					if yielded_count >= limit:
						# Limit reached
						return
				else:
					break