-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: meilisearch backend for notes search
This is a very simple and basic backend. It is based on Django signals, just like the Elasticsearch backend. But it is much simpler, in the sense that there are just two signals: one for saving documents and one for deletion. This backend is limited, in the sense that it does not support highlighting -- but that's probably not such a big deal. To start using this backend, define the following settings: ES_DISABLED = True MEILISEARCH_ENABLED = True MEILISEARCH_URL = "http://meilisearch:7700" MEILISEARCH_API_KEY = "s3cr3t" MEILISEARCH_INDEX = "tutor_student_notes"
- Loading branch information
Showing
11 changed files
with
540 additions
and
157 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
from unittest.mock import Mock, patch | ||
|
||
from django.test import TestCase | ||
|
||
from notesapi.v1.models import Note | ||
from notesapi.v1.views import meilisearch | ||
|
||
|
||
class MeilisearchTest(TestCase): | ||
|
||
@classmethod | ||
def setUpClass(cls): | ||
super().setUpClass() | ||
meilisearch.connect_signals() | ||
|
||
@classmethod | ||
def tearDownClass(cls): | ||
super().tearDownClass() | ||
meilisearch.disconnect_signals() | ||
|
||
def setUp(self): | ||
self.enterContext( | ||
patch.object(meilisearch.Client, "meilisearch_client", Mock()) | ||
) | ||
self.enterContext(patch.object(meilisearch.Client, "meilisearch_index", Mock())) | ||
|
||
@property | ||
def note_dict(self): | ||
return { | ||
"user": "test_user_id", | ||
"usage_id": "i4x://org/course/html/52aa9816425a4ce98a07625b8cb70811", | ||
"course_id": "org/course/run", | ||
"text": "test note text", | ||
"quote": "test note quote", | ||
"ranges": [ | ||
{ | ||
"start": "/p[1]", | ||
"end": "/p[1]", | ||
"startOffset": 0, | ||
"endOffset": 10, | ||
} | ||
], | ||
"tags": ["apple", "pear"], | ||
} | ||
|
||
def test_save_delete_note(self): | ||
note = Note.create(self.note_dict) | ||
note.save() | ||
note_id = note.id | ||
|
||
meilisearch.Client.meilisearch_index.add_documents.assert_called_with( | ||
[ | ||
{ | ||
"id": note_id, | ||
"user_id": "test_user_id", | ||
"course_id": "org/course/run", | ||
"text": "test note text", | ||
} | ||
] | ||
) | ||
|
||
note.delete() | ||
meilisearch.Client.meilisearch_index.delete_document.assert_called_with(note_id) | ||
|
||
def test_get_queryset_no_result(self): | ||
queryset = meilisearch.AnnotationSearchView().get_queryset() | ||
assert not queryset.all() | ||
|
||
def test_get_queryset_one_match(self): | ||
note1 = Note.create(self.note_dict) | ||
note2 = Note.create(self.note_dict) | ||
note1.save() | ||
note2.save() | ||
view = meilisearch.AnnotationSearchView() | ||
view.params = { | ||
"text": "dummy text", | ||
"user": "someuser", | ||
"course_id": "course/id", | ||
"page_size": 10, | ||
"page": 2, | ||
} | ||
with patch.object( | ||
meilisearch.Client.meilisearch_index, | ||
"search", | ||
Mock(return_value={"hits": [{"id": note2.id}]}), | ||
) as mock_search: | ||
queryset = view.get_queryset() | ||
mock_search.assert_called_once_with( | ||
"dummy text", | ||
{ | ||
"offset": 10, | ||
"limit": 10, | ||
"filter": ["user_id = 'someuser'", "course_id = 'course/id'"], | ||
}, | ||
) | ||
assert [note2.id] == [note.id for note in queryset] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,26 @@ | ||
import typing as t | ||
from django.conf import settings | ||
|
||
from .common import ( | ||
AnnotationDetailView, | ||
AnnotationListView, | ||
AnnotationRetireView, | ||
AnnotationSearchView | ||
) | ||
|
||
from .exceptions import SearchViewRuntimeError | ||
|
||
def get_views_module(): | ||
|
||
# pylint: disable=import-outside-toplevel | ||
def get_annotation_search_view_class() -> t.Type[AnnotationSearchView]: | ||
""" | ||
Import views from either mysql or elasticsearch backend | ||
Import views from either mysql, elasticsearch or meilisearch backend | ||
""" | ||
if settings.ES_DISABLED: | ||
from . import common as backend_module | ||
else: | ||
from . import elasticsearch as backend_module | ||
return backend_module | ||
if getattr(settings, "MEILISEARCH_ENABLED", False): | ||
from . import meilisearch | ||
return meilisearch.AnnotationSearchView | ||
else: | ||
return AnnotationSearchView | ||
from . import elasticsearch | ||
return elasticsearch.AnnotationSearchView |
Oops, something went wrong.