Skip to content

Commit 272b50a

Browse files
committed
implementing project search, test and travis fix
1 parent 6410495 commit 272b50a

File tree

8 files changed

+93
-30
lines changed

8 files changed

+93
-30
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ python:
44
- 3.6
55
sudo: false
66
env:
7-
- ES_VERSION=1.3.9 ES_DOWNLOAD_URL=https://download.elastic.co/elasticsearch/elasticsearch/elasticsearch-${ES_VERSION}.tar.gz
7+
- ES_VERSION=6.2.4 ES_DOWNLOAD_URL=https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-${ES_VERSION}.tar.gz
88
matrix:
99
include:
1010
- python: 2.7

readthedocs/search/documents.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,44 @@
22

33
from readthedocs.projects.models import Project
44

5-
project = Index('project')
5+
from readthedocs.search.faceted_search import ProjectSearch
66

7-
project.settings(
7+
project_index = Index('project')
8+
9+
project_index.settings(
810
number_of_shards=1,
911
number_of_replicas=0
1012
)
1113

1214

13-
@project.doc_type
15+
@project_index.doc_type
1416
class ProjectDocument(DocType):
1517

1618
class Meta:
1719
model = Project
18-
fields = ('name', 'slug', 'description', 'language')
20+
fields = ('name', 'slug', 'description')
1921

2022
url = fields.TextField()
2123
users = fields.NestedField(properties={
2224
'username': fields.TextField(),
2325
'id': fields.IntegerField(),
2426
})
27+
language = fields.KeywordField()
2528

2629
def prepare_url(self, instance):
2730
return instance.get_absolute_url()
31+
32+
@classmethod
33+
def faceted_search(cls, query, language=None, using=None, index=None):
34+
kwargs = {
35+
'using': using or cls._doc_type.using,
36+
'index': index or cls._doc_type.index,
37+
'doc_types': [cls],
38+
'model': cls._doc_type.model,
39+
'query': query
40+
}
41+
42+
if language:
43+
kwargs['filters'] = {'language': language}
44+
45+
return ProjectSearch(**kwargs)

readthedocs/search/faceted_search.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from elasticsearch_dsl import FacetedSearch, TermsFacet
2+
3+
4+
class ProjectSearch(FacetedSearch):
5+
fields = ['name^5', 'description']
6+
facets = {
7+
'language': TermsFacet(field='language')
8+
}
9+
10+
def __init__(self, using, index, doc_types, model, **kwargs):
11+
self.using = using
12+
self.index = index
13+
self.doc_types = doc_types
14+
self._model = model
15+
super(ProjectSearch, self).__init__(**kwargs)

readthedocs/search/tests/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def mock_elastic_index(mocker):
1616
mocker.patch.object(Index, '_index', index_name.lower())
1717

1818

19-
@pytest.fixture(autouse=True)
19+
@pytest.fixture()
2020
def es_index(mock_elastic_index):
2121
# Create the index.
2222
index = Index()

readthedocs/search/tests/test_views.py

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
import random
2+
import string
3+
14
import pytest
25
from django.core.management import call_command
36
from django.core.urlresolvers import reverse
47
from django_dynamic_fixture import G
8+
from django_elasticsearch_dsl import Index
59
from pyquery import PyQuery as pq
10+
from pytest_mock import mock
611

712
from readthedocs.builds.constants import LATEST
813
from readthedocs.builds.models import Version
@@ -12,13 +17,9 @@
1217

1318
@pytest.mark.django_db
1419
@pytest.mark.search
15-
class TestElasticSearch(object):
20+
class TestProjectSearch(object):
1621
url = reverse('search')
1722

18-
def _reindex_elasticsearch(self, es_index):
19-
call_command('reindex_elasticsearch')
20-
es_index.refresh_index()
21-
2223
def _get_search_result(self, url, client, search_params):
2324
resp = client.get(url, search_params)
2425
assert resp.status_code == 200
@@ -27,21 +28,24 @@ def _get_search_result(self, url, client, search_params):
2728
result = page.find('.module-list-wrapper .module-item-title')
2829
return result, page
2930

30-
@pytest.fixture(autouse=True)
31-
def elastic_index(self, mock_parse_json, all_projects, es_index):
32-
self._reindex_elasticsearch(es_index=es_index)
31+
# TODO: Implement a way to generate unique index name in test
32+
# @pytest.fixture(autouse=True)
33+
# def mock_project_index(self, mocker):
34+
# mocked_document = mocker.patch('readthedocs.search.documents.get_index')
35+
# index_name = ''.join([random.choice(string.ascii_letters) for _ in range(5)])
36+
#
37+
# mocked_document.return_value = Index(index_name)
3338

3439
def test_search_by_project_name(self, client, project):
3540
result, _ = self._get_search_result(url=self.url, client=client,
3641
search_params={'q': project.name})
3742

3843
assert project.name.encode('utf-8') in result.text().encode('utf-8')
3944

40-
def test_search_project_show_languages(self, client, project, es_index):
45+
def test_search_project_show_languages(self, client, project):
4146
"""Test that searching project should show all available languages"""
4247
# Create a project in bn and add it as a translation
4348
G(Project, language='bn', name=project.name)
44-
self._reindex_elasticsearch(es_index=es_index)
4549

4650
result, page = self._get_search_result(url=self.url, client=client,
4751
search_params={'q': project.name})
@@ -51,11 +55,10 @@ def test_search_project_show_languages(self, client, project, es_index):
5155
assert len(content) == 2
5256
assert 'bn' in content.text()
5357

54-
def test_search_project_filter_language(self, client, project, es_index):
58+
def test_search_project_filter_language(self, client, project):
5559
"""Test that searching project filtered according to language"""
5660
# Create a project in bn and add it as a translation
5761
translate = G(Project, language='bn', name=project.name)
58-
self._reindex_elasticsearch(es_index=es_index)
5962
search_params = {'q': project.name, 'language': 'bn'}
6063

6164
result, page = self._get_search_result(url=self.url, client=client,
@@ -65,10 +68,33 @@ def test_search_project_filter_language(self, client, project, es_index):
6568
assert len(result) == 1
6669

6770
content = page.find('.navigable .language-list')
68-
# There should be 1 languages
69-
assert len(content) == 1
71+
# There should be 2 languages because both `en` and `bn` should show there
72+
assert len(content) == 2
7073
assert 'bn' in content.text()
7174

75+
76+
@pytest.mark.django_db
77+
@pytest.mark.search
78+
@pytest.mark.xfail("File search not work still!")
79+
class TestElasticSearch(object):
80+
url = reverse('search')
81+
82+
def _reindex_elasticsearch(self, es_index):
83+
call_command('reindex_elasticsearch')
84+
es_index.refresh_index()
85+
86+
def _get_search_result(self, url, client, search_params):
87+
resp = client.get(url, search_params)
88+
assert resp.status_code == 200
89+
90+
page = pq(resp.content)
91+
result = page.find('.module-list-wrapper .module-item-title')
92+
return result, page
93+
94+
@pytest.fixture()
95+
def elastic_index(self, mock_parse_json, all_projects, es_index):
96+
self._reindex_elasticsearch(es_index=es_index)
97+
7298
@pytest.mark.parametrize('data_type', ['content', 'headers', 'title'])
7399
@pytest.mark.parametrize('page_num', [0, 1])
74100
def test_search_by_file_content(self, client, project, data_type, page_num):

readthedocs/search/views.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
from readthedocs.builds.constants import LATEST
1414
from readthedocs.search import lib as search_lib
15+
from readthedocs.search.documents import ProjectDocument
1516

1617
log = logging.getLogger(__name__)
1718
LOG_TEMPLATE = u'(Elastic Search) [{user}:{type}] [{project}:{version}:{language}] {msg}'
@@ -45,14 +46,18 @@ def elastic_search(request):
4546

4647
if user_input.query:
4748
if user_input.type == 'project':
48-
results = search_lib.search_project(
49-
request, user_input.query, language=user_input.language)
49+
project_search = ProjectDocument.faceted_search(query=user_input.query,
50+
language=user_input.language)
51+
response = project_search.execute()
52+
results = response.hits
53+
facets = response.facets
5054
elif user_input.type == 'file':
5155
results = search_lib.search_file(
5256
request, user_input.query, project_slug=user_input.project,
5357
version_slug=user_input.version, taxonomy=user_input.taxonomy)
5458

55-
if results:
59+
# TODO: Temporary until finishing search upgrade for files
60+
if results and user_input.type == 'file':
5661
# pre and post 1.0 compat
5762
for num, hit in enumerate(results['hits']['hits']):
5863
for key, val in list(hit['fields'].items()):

readthedocs/templates/search/elastic_search.html

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626

2727
{% if facets.language %}
2828
<h5> Language </h5>
29-
{% for name, count in facets.language.items %}
30-
<li class="{% if language == name %}active{% endif %} language-list">
29+
{% for name, count, selected in facets.language %}
30+
<li class="{% if selected %}active{% endif %} language-list">
3131
{% if language == name %}
3232
<a href="?{% url_replace request 'language' '' %}">{{ name }}
3333
{% else %}
@@ -141,14 +141,14 @@ <h3>{% blocktrans with query=query|default:"" %}Results for {{ query }}{% endblo
141141
<div class="module-list-wrapper">
142142

143143
<ul>
144-
{% for result in results.hits.hits %}
144+
{% for result in results %}
145145
<li class="module-item">
146146
<p class="module-item-title">
147-
{% if result.fields.name %}
147+
{% if result.name %}
148148

149149
{# Project #}
150-
<a href="{{ result.fields.url }}">{{ result.fields.name }}</a>
151-
{% for fragment in result.highlight.description|slice:":3" %}
150+
<a href="{{ result.url }}">{{ result.name }}</a>
151+
{% for fragment in result.description|slice:":3" %}
152152
<p>
153153
...{{ fragment|safe }}...
154154
</p>

scripts/travis/install_elasticsearch.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@ if [ $ES_DOWNLOAD_URL ]
22
then
33
wget ${ES_DOWNLOAD_URL}
44
tar -xzf elasticsearch-${ES_VERSION}.tar.gz
5-
./elasticsearch-${ES_VERSION}/bin/plugin -install elasticsearch/elasticsearch-analysis-icu/2.3.0
65
./elasticsearch-${ES_VERSION}/bin/elasticsearch &
76
fi

0 commit comments

Comments
 (0)