mirror of
https://github.com/Alexander-D-Karpov/akarpov
synced 2024-11-22 01:36:33 +03:00
added music search, major improvements on file search
This commit is contained in:
parent
4a407dfc06
commit
af5f1f8afc
|
@ -1,4 +1,4 @@
|
|||
from django_elasticsearch_dsl import Document
|
||||
from django_elasticsearch_dsl import Document, fields
|
||||
from django_elasticsearch_dsl.registries import registry
|
||||
|
||||
from akarpov.files.models import File
|
||||
|
@ -6,26 +6,41 @@
|
|||
|
||||
@registry.register_document
|
||||
class FileDocument(Document):
|
||||
class Index:
|
||||
name = "files"
|
||||
settings = {"number_of_shards": 1, "number_of_replicas": 0}
|
||||
name = fields.TextField(
|
||||
attr="name",
|
||||
fields={
|
||||
"raw": fields.KeywordField(normalizer="lowercase"),
|
||||
},
|
||||
)
|
||||
|
||||
description = fields.TextField(
|
||||
attr="description",
|
||||
fields={
|
||||
"raw": fields.KeywordField(normalizer="lowercase"),
|
||||
},
|
||||
)
|
||||
|
||||
content = fields.TextField(
|
||||
attr="content",
|
||||
fields={
|
||||
"raw": fields.KeywordField(normalizer="lowercase"),
|
||||
},
|
||||
)
|
||||
|
||||
class Django:
|
||||
model = File
|
||||
fields = [
|
||||
"name",
|
||||
"description",
|
||||
"content",
|
||||
]
|
||||
|
||||
def prepare_description(self, instance):
|
||||
# This method is called for every instance before indexing
|
||||
return instance.description or ""
|
||||
|
||||
def prepare_content(self, instance):
|
||||
# This method is called for every instance before indexing
|
||||
# check instance.content is not None
|
||||
return (
|
||||
instance.content.decode("utf-8")
|
||||
if isinstance(instance.content, bytes)
|
||||
else instance.content
|
||||
if instance.content and isinstance(instance.content, bytes)
|
||||
else ""
|
||||
)
|
||||
|
||||
class Index:
|
||||
name = "files"
|
||||
settings = {"number_of_shards": 1, "number_of_replicas": 0}
|
||||
|
|
|
@ -40,13 +40,16 @@ def search(self, query: str):
|
|||
ES_Q(
|
||||
"multi_match",
|
||||
query=query,
|
||||
fields=["name", "description", "content"],
|
||||
fields=["name^3", "description^2", "content"],
|
||||
type="best_fields",
|
||||
fuzziness="AUTO",
|
||||
),
|
||||
ES_Q("match_phrase_prefix", name=query),
|
||||
ES_Q("wildcard", name=f"*{query}*"),
|
||||
ES_Q("wildcard", description=f"*{query}*"),
|
||||
ES_Q("wildcard", content=f"*{query}*"),
|
||||
ES_Q("wildcard", name__raw=f"*{query.lower()}*"),
|
||||
ES_Q("wildcard", description__raw=f"*{query.lower()}*"),
|
||||
ES_Q("wildcard", content__raw=f"*{query.lower()}*"),
|
||||
ES_Q("wildcard", file_type__raw=f"*{query.lower()}*"),
|
||||
ES_Q("wildcard", file_obj__raw=f"*{query.lower()}*"),
|
||||
ES_Q("wildcard", preview__raw=f"*{query.lower()}*"),
|
||||
],
|
||||
minimum_should_match=1,
|
||||
)
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
SongUserRating,
|
||||
UserListenHistory,
|
||||
)
|
||||
from akarpov.music.services.search import search_song
|
||||
from akarpov.music.tasks import listen_to_song
|
||||
|
||||
|
||||
|
@ -83,7 +84,11 @@ class ListCreateSongAPIView(LikedSongsContextMixin, generics.ListCreateAPIView):
|
|||
pagination_class = StandardResultsSetPagination
|
||||
|
||||
def get_queryset(self):
|
||||
qs = Song.objects.cache()
|
||||
search = self.request.query_params.get("search", None)
|
||||
if search:
|
||||
qs = search_song(search)
|
||||
else:
|
||||
qs = Song.objects.cache()
|
||||
|
||||
if "sort" in self.request.query_params:
|
||||
sorts = self.request.query_params["sort"].split(",")
|
||||
|
@ -111,6 +116,12 @@ def get_queryset(self):
|
|||
|
||||
@extend_schema(
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="search",
|
||||
description="Search query",
|
||||
required=False,
|
||||
type=str,
|
||||
),
|
||||
OpenApiParameter(
|
||||
name="sort",
|
||||
description="Sorting algorithm",
|
||||
|
|
67
akarpov/music/documents.py
Normal file
67
akarpov/music/documents.py
Normal file
|
@ -0,0 +1,67 @@
|
|||
from django_elasticsearch_dsl import Document, fields
|
||||
from django_elasticsearch_dsl.registries import registry
|
||||
|
||||
from akarpov.music.models import Song
|
||||
|
||||
|
||||
@registry.register_document
|
||||
class SongDocument(Document):
|
||||
authors = fields.NestedField(
|
||||
attr="authors",
|
||||
properties={
|
||||
"name": fields.TextField(
|
||||
fields={
|
||||
"raw": fields.KeywordField(normalizer="lowercase"),
|
||||
},
|
||||
),
|
||||
"link": fields.TextField(),
|
||||
"meta": fields.ObjectField(dynamic=True),
|
||||
},
|
||||
)
|
||||
|
||||
album = fields.NestedField(
|
||||
attr="album",
|
||||
properties={
|
||||
"name": fields.TextField(
|
||||
fields={
|
||||
"raw": fields.KeywordField(normalizer="lowercase"),
|
||||
},
|
||||
),
|
||||
"link": fields.TextField(),
|
||||
"meta": fields.ObjectField(dynamic=True),
|
||||
},
|
||||
)
|
||||
|
||||
name = fields.TextField(
|
||||
attr="name",
|
||||
fields={
|
||||
"raw": fields.KeywordField(normalizer="lowercase"),
|
||||
},
|
||||
)
|
||||
|
||||
meta = fields.ObjectField(dynamic=True) # Added meta field here as dynamic object
|
||||
|
||||
class Index:
|
||||
name = "songs"
|
||||
settings = {"number_of_shards": 1, "number_of_replicas": 0}
|
||||
# settings = {
|
||||
# "number_of_shards": 1,
|
||||
# "number_of_replicas": 0,
|
||||
# "analysis": {
|
||||
# "analyzer": {
|
||||
# "russian_icu": {
|
||||
# "type": "custom",
|
||||
# "tokenizer": "icu_tokenizer",
|
||||
# "filter": ["icu_folding","icu_normalizer"]
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# } TODO
|
||||
|
||||
class Django:
|
||||
model = Song
|
||||
|
||||
def get_instances_from_related(self, related_instance):
|
||||
if isinstance(related_instance, Song):
|
||||
return related_instance.album
|
||||
return related_instance.songs.all()
|
47
akarpov/music/services/search.py
Normal file
47
akarpov/music/services/search.py
Normal file
|
@ -0,0 +1,47 @@
|
|||
from django.db.models import Case, When
|
||||
from elasticsearch_dsl import Q as ES_Q
|
||||
|
||||
from akarpov.music.documents import SongDocument
|
||||
from akarpov.music.models import Song
|
||||
|
||||
|
||||
def search_song(query):
|
||||
search = SongDocument.search()
|
||||
search_query = ES_Q(
|
||||
"bool",
|
||||
should=[
|
||||
ES_Q(
|
||||
"multi_match",
|
||||
query=query,
|
||||
fields=["name^3", "authors.name^2", "album.name"],
|
||||
fuzziness="AUTO",
|
||||
), # Change here
|
||||
ES_Q("wildcard", name__raw=f"*{query.lower()}*"),
|
||||
ES_Q(
|
||||
"nested",
|
||||
path="authors",
|
||||
query=ES_Q("wildcard", authors__name__raw=f"*{query.lower()}*"),
|
||||
),
|
||||
ES_Q(
|
||||
"nested",
|
||||
path="album",
|
||||
query=ES_Q("wildcard", album__name__raw=f"*{query.lower()}*"),
|
||||
),
|
||||
],
|
||||
minimum_should_match=1,
|
||||
)
|
||||
|
||||
search = search.query(search_query)
|
||||
|
||||
response = search.execute()
|
||||
|
||||
# Check for hits and get song instances
|
||||
if response.hits:
|
||||
hit_ids = [hit.meta.id for hit in response.hits]
|
||||
songs = Song.objects.filter(id__in=hit_ids).order_by(
|
||||
Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(hit_ids)])
|
||||
)
|
||||
|
||||
return songs
|
||||
|
||||
return Song.objects.none()
|
Loading…
Reference in New Issue
Block a user