from typing import List, Type from api import elastic_search, app from utils.decorators import retry from models import Campaign, Project, CampaignAd, PRSPurchaseOrder from models.mixins.searchable import SearchableMixin class ElasticSearchIndexer: models_to_index: List[SearchableMixin] = [Project, Campaign, CampaignAd, PRSPurchaseOrder] index_settings: dict MIN_GRAM_LENGTH = 1 MAX_GRAM_LENGTH = 50 def __init__(self, models: List[Type[SearchableMixin]] = None, settings: dict = None, mappings: dict = None): if models: self.models_to_index = models self.index_settings = self.common_index_settings() self.mapping_settings = self.common_mapping_settings() if settings: self.index_settings.update(settings) if mappings: self.mapping_settings.update(mappings) def common_index_settings(self) -> dict: return { "max_ngram_diff": "50", "analysis": { "filter": { "ngram_filter": { "type": "edge_ngram", "min_gram": self.MIN_GRAM_LENGTH, "max_gram": self.MAX_GRAM_LENGTH, "token_chars": ["letter", "digit", "punctuation", "symbol"], } }, "analyzer": { "autocomplete": { "type": "custom", "tokenizer": "standard", "filter": ["lowercase", "ngram_filter", "asciifolding"], } }, }, } def common_mapping_settings(self) -> dict: return {"properties": {}} @retry(Exception, tries=5, delay=2) def reindex_database(self, model_to_reindex=None): if model_to_reindex is not None and model_to_reindex in self.models_to_index: self.models_to_index = [model_to_reindex] app.logger.info(f"[ES] Starting partial ElasticSearch reindex for model {model_to_reindex.__name__}") else: app.logger.info("[ES] Starting full ElasticSearch reindex") for model_class in self.models_to_index: app.logger.info(f"[ES] Reindexing {model_class}") elastic_search.indices.delete(index=model_class.elastic_index(), ignore_unavailable=True, ignore=[111]) elastic_search.indices.create( index=model_class.elastic_index(), body={ "settings": self.index_settings, "mappings": {**self.mapping_settings, "properties": model_class.__searchable__}, }, ignore=[111], ) model_class.reindex() app.logger.info("[ES] Full ElasticSearch reindex completed")