Пример #1
0
    def apply_filter(query_value, filters, ignore_bbox=False, only_site=False):
        """
        Apply filter and do the search to biological collection
        record and location site

        :param query_value: str
        :param filters: dict
        :param ignore_bbox: bool
        :returns:
        - collection_results : results from bio collection record
        - site_results : results from location site
        - fuzzy_search : if results from search is fuzzy search
        """

        fuzzy_search = False
        user_boundaries = None
        filter_mode = False

        sqs = SearchQuerySet()
        settings.ELASTIC_MIN_SCORE = 0

        # All filters
        taxon = filters.get('taxon', None)
        bbox = filters.get('bbox', None)
        query_collector = filters.get('collector', None)
        boundary = filters.get('boundary', None)
        user_boundary = filters.get('userBoundary', None)
        query_category = filters.get('category', None)
        reference_category = filters.get('referenceCategory', None)
        reference = filters.get('reference', None)
        year_from = filters.get('yearFrom', None)
        year_to = filters.get('yearTo', None)
        months = filters.get('months', None)
        site_id = filters.get('siteId', None)
        endemic = filters.get('endemic', None)
        conservation_status = filters.get('conservationStatus', None)
        river_catchments = filters.get('riverCatchment', None)

        if (
                taxon or
                query_collector or
                boundary or user_boundary or
                query_category or reference_category or
                year_from or year_to or
                months or reference or
                conservation_status or
                river_catchments or
                site_id or endemic):
            filter_mode = True

        if query_value:
            clean_query = sqs.query.clean(query_value)
            results = sqs.filter(
                SQ(original_species_name_exact__contains=clean_query) |
                SQ(taxon_scientific_name_exact__contains=clean_query) |
                SQ(vernacular_names__contains=clean_query),
                validated=True
            ).models(BiologicalCollectionRecord)

            if len(results) > 0:
                fuzzy_search = False
            else:
                fuzzy_search = True
                # Set min score bigger for fuzzy search
                settings.ELASTIC_MIN_SCORE = 2
                results = sqs.filter(
                    SQ(original_species_name=clean_query),
                    validated=True
                ).models(BiologicalCollectionRecord)
                settings.ELASTIC_MIN_SCORE = 0
        else:
            if filter_mode:
                results = sqs.all().models(
                    BiologicalCollectionRecord)
                results = results.filter(validated=True)
            else:
                results = []

        if taxon:
            results = sqs.filter(
                taxonomy=taxon
            ).models(BiologicalCollectionRecord)

        # get by bbox
        if not ignore_bbox:
            if bbox:
                bbox_array = bbox.split(',')
                downtown_bottom_left = Point(
                    float(bbox_array[1]),
                    float(bbox_array[0]))

                downtown_top_right = Point(
                    float(bbox_array[3]),
                    float(bbox_array[2]))

                results = results.within(
                    'location_center',
                    downtown_bottom_left,
                    downtown_top_right)

        # additional filters
        # query by collectors
        if query_collector:
            qs_collector = SQ()
            qs = json.loads(query_collector)
            for query in qs:
                qs_collector.add(SQ(collector=query), SQ.OR)
            results = results.filter(qs_collector)

        if boundary:
            qs_collector = SQ()
            qs = json.loads(boundary)
            for query in qs:
                query = '_' + query + '_'
                qs_collector.add(SQ(boundary__contains=query), SQ.OR)
            results = results.filter(qs_collector)

        if user_boundary:
            qs = json.loads(user_boundary)
            user_boundaries = UserBoundary.objects.filter(
                pk__in=qs
            )
            for user_boundary in user_boundaries:
                for geom in user_boundary.geometry:
                    results = results.polygon(
                        'location_center',
                        geom
                    )

        # query by category
        if query_category:
            qs_category = SQ()
            qs = json.loads(query_category)
            for query in qs:
                qs_category.add(SQ(category=query), SQ.OR)
            results = results.filter(qs_category)

        # query by endemic
        if endemic:
            qs_endemism = SQ()
            qs = json.loads(endemic)
            for query in qs:
                qs_endemism.add(SQ(endemism=query), SQ.OR)
            results = results.filter(qs_endemism)

        # query by conservation status
        if conservation_status:
            qs_conservation_status = SQ()
            qs = json.loads(conservation_status)
            for query in qs:
                qs_conservation_status.add(SQ(iucn_status=query), SQ.OR)
            results = results.filter(qs_conservation_status)

        # query by river catchment
        if river_catchments:
            qs_river_catchment = SQ()
            qs = json.loads(river_catchments)
            for query in qs:
                query = '_' + query.replace(' ', '_') + '_'
                qs_river_catchment.add(SQ(river_catchments__contains=query),
                                       SQ.OR)
            results = results.filter(qs_river_catchment)

        # query by reference category
        if reference_category:
            qs_reference_category = SQ()
            qs = json.loads(reference_category)
            for query in qs:
                qs_reference_category.add(SQ(reference_category=query), SQ.OR)
            results = results.filter(qs_reference_category)

        # query by reference category
        if reference:
            qs_reference = SQ()
            qs = json.loads(reference)
            for query in qs:
                qs_reference.add(SQ(reference__exact=query),
                                 SQ.OR)
            results = results.filter(qs_reference)

        # query by year from
        if year_from:
            clean_query_year_from = sqs.query.clean(year_from)
            results = results.filter(
                collection_date_year__gte=clean_query_year_from)

        # query by year to
        if year_to:
            clean_query_year_to = sqs.query.clean(year_to)
            results = results.filter(
                collection_date_year__lte=clean_query_year_to)

        # query by months
        if months:
            qs = months.split(',')
            qs_month = SQ()
            for month in qs:
                clean_query_month = sqs.query.clean(month)
                qs_month.add(
                    SQ(collection_date_month=clean_query_month), SQ.OR)
            results = results.filter(qs_month)

        # Search by site id
        if site_id:
            site_ids = site_id.split(',')
            qs_site_id = SQ()
            for site in site_ids:
                qs_site_id.add(
                    SQ(site_id_indexed=site), SQ.OR
                )
            results = results.filter(
                qs_site_id
            ).models(BiologicalCollectionRecord)

        collection_results = results

        # Search location site by name
        location_site_search = EmptySearchQuerySet()
        if query_value:
            location_site_search = SearchQuerySet().filter(
                site_name__contains=query_value
            ).models(LocationSite)

        location_site_results = location_site_search
        location_site_user_boundary = EmptySearchQuerySet()

        if boundary:
            qs_collector = SQ()
            qs = json.loads(boundary)
            for query in qs:
                query = '_' + query + '_'
                qs_collector.add(SQ(boundary__contains=query), SQ.OR)
            if isinstance(location_site_results, SearchQuerySet):
                location_site_results = location_site_results.filter(
                    qs_collector)

        if user_boundaries and isinstance(location_site_search,
                                          SearchQuerySet):
            location_site_user_boundary = location_site_search
            for user_boundary in user_boundaries:
                for geom in user_boundary.geometry:
                    location_site_user_boundary = \
                        location_site_user_boundary.polygon(
                            'location_site_point',
                            geom)

        site_results = GetCollectionAbstract.combine_search_query_results(
            location_site_results,
            location_site_user_boundary
        )

        if len(site_results) > 0 or isinstance(
                location_site_user_boundary, SearchQuerySet):
            # If there are fuzzy results from collection search but we
            # got non fuzzy results from location site, then remove
            # all the fuzzy results from collection
            if fuzzy_search and \
                    len(collection_results) > 0:
                collection_results = []
            fuzzy_search = False

        return collection_results, site_results, fuzzy_search