django-haystack / django-haystack/django-haystack

within search fails when the bounding box crosses the anti-meridian on solr

Open
#1,607 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
3.7k
Forks
1.3k
Avg merge
3h 18m
Merged PRs (30d)
3

Description

  • Tested with the latest Haystack release
  • Tested with the current Haystack master branch

Expected behaviour

Doing a spatial search using within it takes the bottom left and top right which implies a bounding box. Doing a within search should give results within the bounding box.

Actual behaviour

No results since it's not doing a true bounding box but checking if points are between a min max latitude.

Steps to reproduce the behaviour

  1. Index some results with points
  2. Do a within query that has a bottom left in the left hemisphere and a top right in the right hemisphere

example bounds:

bounds=u'{"south":18.529137640349763,"west":175.8987575837,"north":53.046193148995805,"east":-88.12467991630001}'

Configuration

  • Operating system version:
  • Search engine version: solr 5
  • Python version:
  • Django version:
  • Haystack version:

Misc

The code responsible is here:

        if within is not None:
            from haystack.utils.geo import generate_bounding_box

            kwargs.setdefault('fq', [])
            ((min_lat, min_lng), (max_lat, max_lng)) = generate_bounding_box(within['point_1'], within['point_2'])
            # Bounding boxes are min, min TO max, max. Solr's wiki was *NOT*
            # very clear on this.
            bbox = '%s:[%s,%s TO %s,%s]' % (within['field'], min_lat, min_lng, max_lat, max_lng)
            kwargs['fq'].append(bbox)

...

def generate_bounding_box(bottom_left, top_right):
    """
    Takes two opposite corners of a bounding box (order matters!) & generates
    a two-tuple of the correct coordinates for the bounding box.

    The two-tuple is in the form ``((min_lat, min_lng), (max_lat, max_lng))``.
    """
    west, lat_1 = bottom_left.get_coords()
    east, lat_2 = top_right.get_coords()
    min_lat, max_lat = min(lat_1, lat_2), max(lat_1, lat_2)
    return ((min_lat, west), (max_lat, east))

It looks like it's just looking for the min/max of latitude and not using the box that was passed in.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the shown within-query handling and generate_bounding_box function, then reproduce the issue using the supplied anti-meridian bounds. Verify how the longitude range is constructed and confirm that a query crossing the anti-meridian returns points inside the bounding box.

Written by the indexing model from the issue text.

Assessment

Tech stack
django, python
Domain
search
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.