Skip to content
This repository has been archived by the owner on Nov 22, 2023. It is now read-only.

Commit

Permalink
(PC-11252) Put educational offers in a separate app search engine
Browse files Browse the repository at this point in the history
  • Loading branch information
cgaunet committed Oct 13, 2021
1 parent a0bf628 commit 449950c
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 1 deletion.
35 changes: 34 additions & 1 deletion src/pcapi/core/search/backends/appsearch.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def get_engine_names():

OFFERS_ENGINE_NAMES = get_engine_names()
OFFERS_META_ENGINE_NAME = "offers-meta"
EDUCATIONAL_OFFERS_ENGINE_NAME = "offers-educational"
OFFERS_SEARCH_PRECISION = 3
OFFERS_SCHEMA = {
"artist": "text",
Expand Down Expand Up @@ -225,8 +226,13 @@ def get_offer_engine(document_or_offer_id: typing.Union[dict, int]) -> str:
"""Return the name of the engine to be used for the given offer."""
if isinstance(document_or_offer_id, int):
offer_id = document_or_offer_id
else:

if isinstance(document_or_offer_id, dict):
if document_or_offer_id["is_educational"]:
return EDUCATIONAL_OFFERS_ENGINE_NAME

offer_id = document_or_offer_id["id"]

n = offer_id % len(OFFERS_ENGINE_NAMES)
return f"offers-{n}"

Expand All @@ -246,6 +252,18 @@ def __init__(self):
schema=OFFERS_SCHEMA,
)

self.educational_offers_engine = AppSearchApiClient(
host=settings.APPSEARCH_HOST,
api_key=settings.APPSEARCH_API_KEY,
meta_engine_name=EDUCATIONAL_OFFERS_ENGINE_NAME,
engine_selector=get_offer_engine,
synonyms=OFFERS_SYNONYM_SET,
field_weights=OFFERS_FIELD_WEIGHTS,
field_boosts=OFFERS_FIELD_BOOSTS,
search_precision=OFFERS_SEARCH_PRECISION,
schema=OFFERS_SCHEMA,
)

self.venues_engine = AppSearchApiClient(
host=settings.APPSEARCH_HOST,
api_key=settings.APPSEARCH_API_KEY,
Expand Down Expand Up @@ -380,6 +398,7 @@ def unindex_offer_ids(self, offer_ids: Iterable[int]) -> None:

def unindex_all_offers(self) -> None:
self.offers_engine.delete_all_documents()
self.educational_offers_engine.delete_all_documents()

def unindex_venue_ids(self, venue_ids: Iterable[int]) -> None:
if not venue_ids:
Expand Down Expand Up @@ -573,6 +592,20 @@ def delete_documents(self, document_ids: Iterable[int]) -> None:
response = requests.delete(self.get_documents_url(engine_name), headers=self.headers, data=data)
response.raise_for_status()

if engine_name in OFFERS_ENGINE_NAMES:
# We don't know if it's an educational offer, a regular offer or a venue.
# If it's an educational offer, the DELETE request above will be a no-op
# and we want to DELETE on the educational offers engine.
# If it's a regular offer, the DELETE request below will be a no-op.
# In both cases we make extra requests, but we cannot easily avoid that since
# we can only have the document id and not an Offer or Venue object.
response = requests.delete(
self.get_documents_url(EDUCATIONAL_OFFERS_ENGINE_NAME),
headers=self.headers,
data=data,
)
response.raise_for_status()

def delete_all_documents(self) -> None:
if settings.IS_PROD:
raise ValueError("You cannot delete all documents on production.")
Expand Down
1 change: 1 addition & 0 deletions src/pcapi/core/search/backends/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ class TestingBackend(AppSearchBackend):
def __init__(self): # pylint: disable=super-init-not-called
self.offers_engine = FakeClient("offers")
self.venues_engine = FakeClient("venues")
self.educational_offers_engine = FakeClient("educational-offers")
self.redis_client = current_app.redis_client
10 changes: 10 additions & 0 deletions src/pcapi/scripts/setup_app_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ def setup_offers_engines():
)


def setup_educational_offers_engines():
backend = appsearch.AppSearchBackend()
setup_engine(backend.offers_engine, engine_names=[appsearch.EDUCATIONAL_OFFER_ENGINE_NAME])


def setup_venues_engine():
backend = appsearch.AppSearchBackend()
setup_engine(backend.venues_engine, engine_names=[appsearch.VENUES_ENGINE_NAME])
Expand Down Expand Up @@ -109,6 +114,11 @@ def get_parser():
offers_subparsers = offers_parser.add_subparsers()
offers_setup = offers_subparsers.add_parser("setup", help="Setup a new engine for offers.")
offers_setup.set_defaults(callback=setup_offers_engines)
educational_offers_setup = offers_subparsers.add_parser(
"setup_educational",
help="Setup a new engine for educational offers.",
)
educational_offers_setup.set_defaults(callback=setup_educational_offers_engines)
offers_index = offers_subparsers.add_parser("index", help="Index offers.")
offers_index.set_defaults(callback=index_offers)

Expand Down
5 changes: 5 additions & 0 deletions tests/core/search/test_backend_appsearch.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,14 @@ def test_unindex_offer_ids(app):
app.redis_client.sadd("search:appsearch:indexed-offer-ids", "1")
with requests_mock.Mocker() as mock:
deleted = mock.delete("https://appsearch.example.com/api/as/v1/engines/offers-1/documents")
deleted_educational = mock.delete(
"https://appsearch.example.com/api/as/v1/engines/offers-educational/documents"
)
backend.unindex_offer_ids([1])
deleted_json = deleted.last_request.json()
deleted_educational_json = deleted_educational.last_request.json()
assert deleted_json == [1]
assert deleted_educational_json == [1]


def test_unindex_all_offers(app):
Expand Down

0 comments on commit 449950c

Please sign in to comment.