Repository: genialis/resolwe-bio
Issue: Feature query fails for many genes

Issue moved from https://github.com/genialis/resolwe-bio-py/issues/78

To reproduce, run:

```py
import resdk
res = resdk.Resolwe(url='https://qa.genialis.com')

res.feature.filter(source="NCBI", query=range(300)) # works
res.feature.filter(source="NCBI", query=range(400)) # fails
```

---

Elastic search traceback:
```
Traceback:

File "/srv/genialis/venv/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  149.                     response = self.process_exception_by_middleware(e, request)

File "/srv/genialis/venv/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  147.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/srv/genialis/venv/lib/python2.7/site-packages/django/views/decorators/csrf.py" in wrapped_view
  58.         return view_func(*args, **kwargs)

File "/srv/genialis/venv/lib/python2.7/site-packages/rest_framework/viewsets.py" in view
  83.             return self.dispatch(request, *args, **kwargs)

File "/srv/genialis/venv/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
  477.             response = self.handle_exception(exc)

File "/srv/genialis/venv/lib/python2.7/site-packages/rest_framework/views.py" in handle_exception
  437.             self.raise_uncaught_exception(exc)

File "/srv/genialis/venv/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
  474.             response = handler(request, *args, **kwargs)

File "/srv/genialis/venv/lib/python2.7/site-packages/resolwe/elastic/viewsets.py" in list_with_post
  158.         return self.paginate_response(search)

File "/srv/genialis/venv/lib/python2.7/site-packages/resolwe/elastic/viewsets.py" in paginate_response
  120.         return Response(serializer.data)

File "/srv/genialis/venv/lib/python2.7/site-packages/rest_framework/serializers.py" in data
  725.         ret = super(ListSerializer, self).data

File "/srv/genialis/venv/lib/python2.7/site-packages/rest_framework/serializers.py" in data
  262.                 self._data = self.to_representation(self.instance)

File "/srv/genialis/venv/lib/python2.7/site-packages/rest_framework/serializers.py" in to_representation
  643.             self.child.to_representation(item) for item in iterable

File "/srv/genialis/venv/lib/python2.7/site-packages/elasticsearch_dsl/search.py" in __iter__
  233.         return iter(self.execute())

File "/srv/genialis/venv/lib/python2.7/site-packages/elasticsearch_dsl/search.py" in execute
  627.                     **self._params

File "/srv/genialis/venv/lib/python2.7/site-packages/elasticsearch/client/utils.py" in _wrapped
  69.             return func(*args, params=params, **kwargs)

File "/srv/genialis/venv/lib/python2.7/site-packages/elasticsearch/client/__init__.py" in search
  539.             doc_type, '_search'), params=params, body=body)

File "/srv/genialis/venv/lib/python2.7/site-packages/elasticsearch/transport.py" in perform_request
  327.                 status, headers, data = connection.perform_request(method, url, params, body, ignore=ignore, timeout=timeout)

File "/srv/genialis/venv/lib/python2.7/site-packages/elasticsearch/connection/http_urllib3.py" in perform_request
  109.             self._raise_error(response.status, raw_data)

File "/srv/genialis/venv/lib/python2.7/site-packages/elasticsearch/connection/base.py" in _raise_error
  113.         raise HTTP_EXCEPTIONS.get(status_code, TransportError)(status_code, error_message, additional_info)

Exception Type: TransportError at /api/kb/feature/search
Exception Value: TransportError(500, u'search_phase_execution_exception', u'maxClauseCount is set to 1024')
```

Changed files:
resolwe_bio/kb/views.py, resolwe_bio/kb/tests/test_feature.py

diff --git a/resolwe_bio/kb/tests/test_feature.py b/resolwe_bio/kb/tests/test_feature.py
index 23163870..f3da78f0 100644
--- a/resolwe_bio/kb/tests/test_feature.py
+++ b/resolwe_bio/kb/tests/test_feature.py
@@ -126,6 +126,10 @@ class FeatureTestCase(APITestCase, ElasticSearchTestCase):
                                     format='json')
         self.assertEqual(len(response.data), 0)
 
+        # Test query with a lot of features.
+        response = self.client.post(FEATURE_SEARCH_URL, {'query': [str(x) for x in range(1024)]}, format='json')
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+
     def test_feature_autocomplete(self):
         FEATURE_AUTOCOMPLETE_URL = reverse('resolwebio-api:kb_feature_autocomplete-list')
 
diff --git a/resolwe_bio/kb/views.py b/resolwe_bio/kb/views.py
index 6ad238e8..5dc604b0 100644
--- a/resolwe_bio/kb/views.py
+++ b/resolwe_bio/kb/views.py
@@ -50,15 +50,14 @@ class FeatureSearchViewSet(ElasticSearchBaseViewSet):
             if not isinstance(query, list):
                 query = [query]
 
-            should = []
-            for item in query:
-                should += [
-                    Q('match', feature_id=item),
-                    Q('match', name=item),
-                    Q('match', aliases=item),
+            search = search.filter(
+                'bool',
+                should=[
+                    Q('terms', feature_id=query),
+                    Q('terms', name=query),
+                    Q('terms', aliases=query),
                 ]
-
-            search = search.query('bool', should=should)
+            )
 
         return search