Fakultas Ilmu Komputer UI
Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
PMPL
Class Project
DIGIPUS
Commits
51f3a1e5
Commit
51f3a1e5
authored
Oct 31, 2020
by
Alfian Fuadi Rafli
Browse files
[
#115
] Material: Search/Query By Author & Description
parent
5b62333e
Changes
4
Show whitespace changes
Inline
Side-by-side
app/models.py
View file @
51f3a1e5
...
...
@@ -50,17 +50,27 @@ class MateriManager(models.Manager):
return
SoftDeletionQuerySet
(
self
.
model
)
def
search
(
self
,
search_text
):
search_vector
=
search
.
SearchVector
(
"title"
,
weight
=
"A"
)
search_vector
=
None
for
field
,
weight
in
Materi
.
SEARCH_INDEX
:
if
search_vector
is
None
:
search_vector
=
search
.
SearchVector
(
field
,
weight
=
weight
)
else
:
search_vector
+=
search
.
SearchVector
(
field
,
weight
=
weight
)
search_query
=
search
.
SearchQuery
(
search_text
)
search_rank
=
search
.
SearchRank
(
search_vector
,
search_query
)
search_result
=
(
self
.
get_queryset
().
filter
(
_search_vector
=
search_query
).
annotate
(
rank
=
search_rank
).
order_by
(
"-rank"
)
self
.
get_queryset
()
.
filter
(
_search_vector
=
search_query
)
.
annotate
(
rank
=
search_rank
)
.
order_by
(
"-rank"
)
)
return
search_result
class
SoftDeletionQuerySet
(
models
.
query
.
QuerySet
):
def
delete
(
self
):
return
super
(
SoftDeletionQuerySet
,
self
).
update
(
deleted_at
=
timezone
.
now
())
...
...
@@ -95,13 +105,32 @@ class Materi(SoftDeleteModel):
_search_vector
=
search
.
SearchVectorField
(
null
=
True
,
editable
=
False
)
SEARCH_INDEX
=
(
(
"title"
,
"A"
),
(
"author"
,
"A"
),
(
"publisher"
,
"C"
),
(
"descriptions"
,
"C"
),
(
"uploader"
,
"D"
),
)
objects
=
MateriManager
()
def
save
(
self
,
*
args
,
**
kwargs
):
super
().
save
(
*
args
,
**
kwargs
)
search_index
=
{
field
:
weight
for
(
field
,
weight
)
in
Materi
.
SEARCH_INDEX
}
if
"update_fields"
in
kwargs
:
is_search_index_updated
=
bool
(
set
(
search_index
.
keys
())
&
set
(
kwargs
[
"update_fields"
])
)
if
(
"update_fields"
not
in
kwargs
)
or
(
is_search_index_updated
):
self
.
_search_vector
=
None
for
field
,
weight
in
search_index
.
items
():
if
self
.
_search_vector
is
None
:
self
.
_search_vector
=
search
.
SearchVector
(
field
,
weight
=
weight
)
else
:
self
.
_search_vector
+=
search
.
SearchVector
(
field
,
weight
=
weight
)
if
"update_fields"
not
in
kwargs
or
"_search_vector"
not
in
kwargs
[
"update_fields"
]:
self
.
_search_vector
=
search
.
SearchVector
(
"title"
,
weight
=
"A"
)
self
.
save
(
update_fields
=
[
"_search_vector"
])
@
property
...
...
app/services.py
View file @
51f3a1e5
...
...
@@ -29,16 +29,7 @@ class DafterKatalogService:
@
staticmethod
def
search_materi
(
get_search
,
lst_materi
,
url
):
url
=
url
+
"&search={0}"
.
format
(
get_search
)
lst_materi
=
(
lst_materi
.
search
(
get_search
)
.
filter
(
Q
(
author__icontains
=
get_search
)
|
Q
(
uploader__name__icontains
=
get_search
)
|
Q
(
descriptions__icontains
=
get_search
)
|
Q
(
publisher__icontains
=
get_search
)
)
.
distinct
()
)
lst_materi
=
lst_materi
.
search
(
get_search
)
return
lst_materi
,
url
@
staticmethod
...
...
app/tests.py
View file @
51f3a1e5
...
...
@@ -89,52 +89,6 @@ class DaftarKatalogTest(TestCase):
resp
=
Materi
.
objects
.
get
(
id
=
materi
.
id
)
self
.
assertEqual
(
resp
,
materi
)
def
test_materi_model_generate_search_vector_after_save
(
self
):
Materi
(
title
=
"Eating book"
).
save
()
search_vector_new_materi
=
list
(
Materi
.
objects
.
values_list
(
"_search_vector"
,
flat
=
True
))
expected_search_vector
=
[
"'book':2A 'eat':1A"
]
self
.
assertSequenceEqual
(
search_vector_new_materi
,
expected_search_vector
)
def
test_search_text_on_empty_database
(
self
):
search_query
=
"test"
search_result
=
list
(
Materi
.
objects
.
search
(
search_query
))
expected_search_result
=
[]
self
.
assertSequenceEqual
(
search_result
,
expected_search_result
)
def
test_search_text_on_unmatched_data
(
self
):
Materi
(
title
=
"test satu sekarang"
).
save
()
Materi
(
title
=
"test dua nanti"
).
save
()
search_query
=
"besok"
search_result
=
list
(
Materi
.
objects
.
search
(
search_query
))
expected_search_result
=
[]
self
.
assertSequenceEqual
(
search_result
,
expected_search_result
)
def
test_search_text_return_list_matched_by_rank
(
self
):
materi_2
=
Materi
(
title
=
"ini lumayan cocok lumayan cocok"
)
materi_2
.
save
()
materi_1
=
Materi
(
title
=
"ini sangat cocok sangat cocok sangat cocok"
)
materi_1
.
save
()
materi_4
=
Materi
(
title
=
"ini tidak"
)
materi_4
.
save
()
materi_3
=
Materi
(
title
=
"ini sedikit cocok"
)
materi_3
.
save
()
search_query
=
"ini cocok"
search_result
=
list
(
Materi
.
objects
.
search
(
search_query
))
expected_search_result
=
[
materi_1
,
materi_2
,
materi_3
]
self
.
assertSequenceEqual
(
search_result
,
expected_search_result
)
class
DaftarKatalogSortingByJumlahUnduhTest
(
TestCase
):
def
setUp
(
self
):
...
...
@@ -3631,6 +3585,151 @@ class MateriRecommendationTest(TestCase):
list
=
[
int
(
id
)
for
id
in
re
.
findall
(
r
"Materi\s(\d+)[^\d]"
,
response
.
content
.
decode
())]
self
.
assertEqual
(
list
,
[
1
,
2
])
class
MateriSearchVectorTest
(
TestCase
):
def
setUp
(
self
):
Materi
.
SEARCH_INDEX
=
((
"title"
,
"A"
),
(
"author"
,
"B"
))
def
test_search_vector_constructed_on_create
(
self
):
materi
=
Materi
(
title
=
"Buku 1"
,
author
=
"Pembuat 1"
)
materi
.
save
()
search_vector_string
=
list
(
Materi
.
objects
.
values_list
(
"_search_vector"
,
flat
=
True
)
)[
0
]
self
.
assertGreaterEqual
(
len
(
search_vector_string
.
split
(
","
)),
1
)
def
test_search_vector_based_on_indexed_attribute
(
self
):
materi
=
Materi
(
title
=
"Buku 1"
,
author
=
"Pembuat 1"
,
descriptions
=
"Deskripsi 1"
)
materi
.
save
()
search_vector_string
=
list
(
Materi
.
objects
.
values_list
(
"_search_vector"
,
flat
=
True
)
)[
0
]
self
.
assertIn
(
"buku"
,
search_vector_string
)
self
.
assertIn
(
"pembuat"
,
search_vector_string
)
def
test_search_vector_not_based_on_unindexed_attribute
(
self
):
materi
=
Materi
(
title
=
"Buku 1"
,
author
=
"Pembuat 1"
,
descriptions
=
"Deskripsi 1"
)
materi
.
save
()
search_vector_string
=
list
(
Materi
.
objects
.
values_list
(
"_search_vector"
,
flat
=
True
)
)[
0
]
self
.
assertNotIn
(
"deskripsi"
,
search_vector_string
)
def
test_search_vector_reconstructed_on_update_indexed_field
(
self
):
materi
=
Materi
(
title
=
"Sebelum reconstruct"
)
materi
.
save
()
search_vector
=
list
(
Materi
.
objects
.
values_list
(
"_search_vector"
,
flat
=
True
))[
0
]
materi
.
title
=
"Setelah reconstruct"
materi
.
save
()
search_vector
=
list
(
Materi
.
objects
.
values_list
(
"_search_vector"
,
flat
=
True
))[
0
]
self
.
assertIn
(
"setelah"
,
search_vector
)
def
test_search_vector_not_reconstructed_on_update_unindexed_field
(
self
):
materi
=
Materi
(
descriptions
=
"sebelum reconstruct"
)
materi
.
save
()
search_vector
=
list
(
Materi
.
objects
.
values_list
(
"_search_vector"
,
flat
=
True
))[
0
]
materi
.
descriptions
=
"sebelum reconstruct"
materi
.
save
()
search_vector
=
list
(
Materi
.
objects
.
values_list
(
"_search_vector"
,
flat
=
True
))[
0
]
self
.
assertNotIn
(
"setelah"
,
search_vector
)
class
MateriSearchTest
(
TestCase
):
def
test_empty_result_on_empty_table
(
self
):
search_query
=
"test"
search_result
=
list
(
Materi
.
objects
.
search
(
search_query
))
expected_search_result
=
[]
self
.
assertSequenceEqual
(
search_result
,
expected_search_result
)
def
test_empty_result_on_unmatched_data
(
self
):
Materi
.
SEARCH_INDEX
=
((
"title"
,
"A"
),
(
"author"
,
"B"
))
Materi
(
title
=
"buku 1"
,
author
=
"bapak 1"
).
save
()
Materi
(
title
=
"artikel 2"
,
author
=
"ibu 1"
).
save
()
search_query
=
"majalah"
search_result
=
list
(
Materi
.
objects
.
search
(
search_query
))
expected_search_result
=
[]
self
.
assertSequenceEqual
(
search_result
,
expected_search_result
)
search_query
=
"kakak"
search_result
=
list
(
Materi
.
objects
.
search
(
search_query
))
expected_search_result
=
[]
self
.
assertSequenceEqual
(
search_result
,
expected_search_result
)
def
test_correct_rank_on_result_tested_by_similiarity_words
(
self
):
Materi
.
SEARCH_INDEX
=
((
"descriptions"
,
"A"
),)
materi_2
=
Materi
(
descriptions
=
"ini lumayan cocok lumayan cocok"
)
materi_2
.
save
()
materi_1
=
Materi
(
descriptions
=
"ini sangat cocok sangat cocok sangat cocok"
)
materi_1
.
save
()
materi_4
=
Materi
(
descriptions
=
"ini tidak"
)
materi_4
.
save
()
materi_3
=
Materi
(
descriptions
=
"ini sedikit cocok"
)
materi_3
.
save
()
search_query
=
"ini cocok"
search_result
=
list
(
Materi
.
objects
.
search
(
search_query
))
expected_search_result
=
[
materi_1
,
materi_2
,
materi_3
]
self
.
assertSequenceEqual
(
search_result
,
expected_search_result
)
def
test_correct_rank_on_result_tested_by_weight
(
self
):
Materi
.
SEARCH_INDEX
=
(
(
"title"
,
"A"
),
(
"author"
,
"C"
),
(
"descriptions"
,
"B"
),
(
"publisher"
,
"D"
),
)
materi_title
=
Materi
(
title
=
"cocok"
)
materi_title
.
save
()
materi_author
=
Materi
(
author
=
"cocok cocok cocok"
)
materi_author
.
save
()
materi_descriptions
=
Materi
(
descriptions
=
"cocok cocok"
)
materi_descriptions
.
save
()
materi_publisher
=
Materi
(
publisher
=
"cocok cocok cocok cocok"
)
materi_publisher
.
save
()
search_query
=
"cocok"
search_result
=
list
(
Materi
.
objects
.
search
(
search_query
))
expected_search_result
=
[
materi_title
,
materi_descriptions
,
materi_author
,
materi_publisher
,
]
self
.
assertSequenceEqual
(
search_result
,
expected_search_result
)
class
BacaNantiTest
(
TestCase
):
def
setUp
(
self
):
self
.
contributor_credential
=
{
...
...
digipus/settings.py
View file @
51f3a1e5
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment