Skip to content

Commit

Permalink
Merge pull request #71 from joeyjurjens/fix-popularity-annotate
Browse files Browse the repository at this point in the history
Fix popularity annotation as it causes weird results due to nested join in count
  • Loading branch information
samar-hassan authored Nov 8, 2024
2 parents ffe1f7e + d22f9c4 commit f13e371
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 8 deletions.
18 changes: 11 additions & 7 deletions oscar_elasticsearch/search/api/product.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from odin.codecs import dict_codec

from django.db.models import QuerySet, Count, Q
from django.db.models import QuerySet, Count, Subquery, OuterRef, IntegerField
from django.utils import timezone

from dateutil.relativedelta import relativedelta
Expand Down Expand Up @@ -64,12 +64,16 @@ def make_documents(self, objects):

# Annotate the queryset with popularity to avoid the need of n+1 queries
objects = objects.annotate(
popularity=Count(
"line",
filter=Q(
line__order__date_placed__gte=timezone.now()
- relativedelta(months=settings.MONTHS_TO_RUN_ANALYTICS)
),
popularity=Subquery(
Line.objects.filter(
product=OuterRef("pk"),
order__date_placed__gte=timezone.now()
- relativedelta(months=settings.MONTHS_TO_RUN_ANALYTICS),
)
.values("product")
.annotate(count=Count("id"))
.values("count"),
output_field=IntegerField(),
)
)

Expand Down
3 changes: 3 additions & 0 deletions oscar_elasticsearch/search/api/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ def search(
search_type=es_settings.SEARCH_QUERY_TYPE,
search_operator=es_settings.SEARCH_QUERY_OPERATOR,
scoring_functions=None,
raw_results=False,
):
search_results = search(
self.get_index_name(),
Expand All @@ -317,6 +318,8 @@ def search(

total_hits = search_results["hits"]["total"]["value"]

if raw_results:
return search_results, total_hits
return self.make_queryset(search_results), total_hits

def facet_search(
Expand Down
47 changes: 46 additions & 1 deletion oscar_elasticsearch/search/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
from django.urls import reverse

from oscar.core.loading import get_class, get_model
from oscar.test.factories import ProductFactory
from oscar.test.factories import (
ProductFactory,
OrderFactory,
OrderLineFactory,
)

import oscar_elasticsearch.search.format
import oscar_elasticsearch.search.utils
Expand Down Expand Up @@ -227,6 +231,47 @@ def create_parent_child_products():
with self.assertNumQueries(23):
call_command("update_index_products")

def test_popularity_based_on_order_lines(self):
products = []
for i in range(5):
product = ProductFactory(
title=f"VERY UNIQUE TITLE - {i + 1}", categories=[]
)
products.append(product)

call_command("update_index_products")

results, total_hits = ProductElasticsearchIndex().search(
query_string="VERY UNIQUE TITLE", raw_results=True
)
self.assertEqual(total_hits, 5)
for hit in results["hits"]["hits"]:
self.assertEqual(
hit["_source"]["popularity"],
None,
"no orders place yet, so popularity should be None",
)

order = OrderFactory()
for i, product in enumerate(products):
quantity = int(product.title.split("-")[-1].strip())
for _ in range(quantity):
OrderLineFactory(order=order, product=product)

call_command("update_index_products")

results, total_hits = ProductElasticsearchIndex().search(
query_string="VERY UNIQUE TITLE", raw_results=True
)
self.assertEqual(total_hits, 5)
for hit in results["hits"]["hits"]:
title = hit["_source"]["title"]
quantity = int(title.split("-")[-1].strip())
self.assertEqual(
hit["_source"]["popularity"],
quantity,
)


class TestBrowsableItems(TestCase):

Expand Down

0 comments on commit f13e371

Please sign in to comment.