ElasticSearch + DRF, ограничение в 10.000, пагинация ответов

Рейтинг: 0Ответов: 0Опубликовано: 06.06.2023

У меня есть проект на drf, с elasticsearch, он очень капризный. Всегда ловил ошибку 10.000 при желании выдать ответов больше чем 10.000, можно сменить на max_result_window на 100.000 и даже на 200.000, но тогда возникает ошибка

RecyclerBytesStreamOutput cannot hold more than 2GB of data

В моей БД 550.000 записей, проидексированы, и работает ок, но мне нужно сделать так, что бы ответы выгружались все, которые он способен найти не используя scroll (сильно замедляет работу и выдачу результатов). Возможно тут нужно использовать search_after? Помогите найти правильный вариант пагинации search_after, как сделать сортировку при TextField?

Ниже код.

documents.py:

@registry.register_document
class ComplaintsDocument(Document):
    docs_complaints = fields.TextField()

    class Index:
        name = 'complaints'
        settings = {
            'number_of_shards': 1,
            'number_of_replicas': 0,
        }

    class Django:
        model = Complaint

views.py:

class ComplaintList(generics.ListAPIView):
    # authentication_classes = [TokenAuthentication]
    # permission_classes = [IsAuthenticated]
    queryset = Complaint.objects.all().order_by('-date')
    serializer_class = ComplaintSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_class = ComplaintFilter
    pagination_class = LimitOffsetPagination
    pagination_class.default_limit = 10
    pagination_class.max_limit = 25
    search_fields = ['docs_complaints', 'docs_solutions', 'docs_prescriptions']
    
    def get(self, request, *args, **kwargs):
        search_after = request.query_params.get('search_after')
      
        if search_after:
            response = self.list(request, *args, **kwargs)
            response['search_after'] = search_after
            return response
        
        
        return self.list(request, *args, **kwargs)


class ComplaintDetail(generics.RetrieveAPIView):
    # authentication_classes = [TokenAuthentication]
    # permission_classes = [IsAuthenticated]
    queryset = Complaint.objects.all().order_by('-date')
    serializer_class = ComplaintSerializer
    lookup_field = 'pk' 

filters.py:

docs_complaints = filters.CharFilter(method='search_docs_complaints', label='Поиск (точное совпадение)')
docs_complaints_2 = filters.CharFilter(method='search_docs_complaints_2', label='Поиск (сходство более 70%)')

def search_docs_complaints(self, queryset, name, value):
        client = Elasticsearch(timeout=60)
        s = Search(using=client, index='complaints')
        s = s.query('multi_match', query=value, fields=['docs_complaints'])
        s = s[0:10000]
        response = s.execute()
        complaint_ids = [hit.meta.id for hit in response.hits]
        queryset = queryset.filter(complaint_id__in=complaint_ids)
        return queryset


def search_docs_complaints_2(self, queryset, name, value):
        client = Elasticsearch(timeout=60)
        s = Search(using=client, index='complaints')
        s = s.query('multi_match', query=value, fields=['docs_complaints'], fuzziness='AUTO')
        s = s[0:10000]
        response = s.execute()
        complaint_ids = [hit.meta.id for hit in response.hits]
        queryset = queryset.filter(complaint_id__in=complaint_ids)
        return queryset

Ответы

Ответов пока нет.