class SearchArticle(SearchDocument): class Meta(BaseMeta): doc_type = ARTICLE_TYPE activities = QEnumArray( 'act', model_field=Article.activities) article_categories = QEnumArray( 'acat', model_field=Article.categories) article_type = QEnum( 'atyp', model_field=Article.article_type) FIELDS = ['activities', 'article_type'] @staticmethod def to_search_document(document, index): search_document = SearchDocument.to_search_document(document, index) if document.redirects_to: return search_document search_document['article_categories'] = document.categories SearchDocument.copy_fields( search_document, document, SearchArticle.FIELDS) return search_document
class SearchArea(SearchDocument): class Meta(BaseMeta): doc_type = AREA_TYPE area_type = QEnum('atyp', model_field=Area.area_type) FIELDS = ['area_type'] @staticmethod def to_search_document(document, index): search_document = SearchDocument.to_search_document( document, index, include_areas=False) if document.redirects_to: return search_document SearchDocument.copy_fields(search_document, document, SearchArea.FIELDS) return search_document
class SearchRoute(SearchDocument): class Meta(BaseMeta): doc_type = ROUTE_TYPE # array of waypoint ids waypoints = QLong('w', is_id=True) # array of user ids users = QLong('u', is_id=True) activities = QEnumArray('act', model_field=Route.activities) elevation_min = QInteger('rmina', range=True) elevation_max = QInteger('rmaxa', range=True) height_diff_up = QInteger('hdif', range=True) height_diff_down = QInteger('ddif', range=True) route_length = QInteger('rlen', range=True) difficulties_height = QInteger('ralt', range=True) height_diff_access = QInteger('rappr', range=True) height_diff_difficulties = QInteger('dhei', range=True) route_types = QEnumArray('rtyp', model_field=Route.route_types) orientations = QEnumArray('fac', model_field=Route.orientations) durations = QEnumRange('time', model_field=Route.durations, enum_mapper=sortable_route_duration_types) glacier_gear = QEnum('glac', model_field=Route.glacier_gear) configuration = QEnumArray('conf', model_field=Route.configuration) ski_rating = QEnumRange('trat', model_field=Route.ski_rating, enum_mapper=sortable_ski_ratings) ski_exposition = QEnumRange('sexpo', model_field=Route.ski_exposition, enum_mapper=sortable_exposition_ratings) labande_ski_rating = QEnumRange('srat', model_field=Route.labande_ski_rating, enum_mapper=sortable_labande_ski_ratings) labande_global_rating = QEnumRange('lrat', model_field=Route.labande_global_rating, enum_mapper=sortable_global_ratings) global_rating = QEnumRange('grat', model_field=Route.global_rating, enum_mapper=sortable_global_ratings) engagement_rating = QEnumRange('erat', model_field=Route.engagement_rating, enum_mapper=sortable_engagement_ratings) risk_rating = QEnumRange('orrat', model_field=Route.risk_rating, enum_mapper=sortable_risk_ratings) equipment_rating = QEnumRange('prat', model_field=Route.equipment_rating, enum_mapper=sortable_equipment_ratings) ice_rating = QEnumRange('irat', model_field=Route.ice_rating, enum_mapper=sortable_ice_ratings) mixed_rating = QEnumRange('mrat', model_field=Route.mixed_rating, enum_mapper=sortable_mixed_ratings) exposition_rock_rating = QEnumRange( 'rexpo', model_field=Route.exposition_rock_rating, enum_mapper=sortable_exposition_rock_ratings) rock_free_rating = QEnumRange('frat', model_field=Route.rock_free_rating, enum_mapper=sortable_climbing_ratings) rock_required_rating = QEnumRange('rrat', model_field=Route.rock_required_rating, enum_mapper=sortable_climbing_ratings) aid_rating = QEnumRange('arat', model_field=Route.aid_rating, enum_mapper=sortable_aid_ratings) via_ferrata_rating = QEnumRange('krat', model_field=Route.via_ferrata_rating, enum_mapper=sortable_via_ferrata_ratings) hiking_rating = QEnumRange('hrat', model_field=Route.hiking_rating, enum_mapper=sortable_hiking_ratings) hiking_mtb_exposition = QEnumRange('hexpo', model_field=Route.hiking_mtb_exposition, enum_mapper=sortable_exposition_ratings) snowshoe_rating = QEnumRange('wrat', model_field=Route.snowshoe_rating, enum_mapper=sortable_snowshoe_ratings) mtb_up_rating = QEnumRange('mbur', model_field=Route.mtb_up_rating, enum_mapper=sortable_mtb_up_ratings) mtb_down_rating = QEnumRange('mbdr', model_field=Route.mtb_down_rating, enum_mapper=sortable_mtb_down_ratings) mtb_length_asphalt = QInteger('mbroad', range=True) mtb_length_trail = QInteger('mbtrack', range=True) mtb_height_diff_portages = QInteger('mbpush', range=True) rock_types = QEnumArray('rock', model_field=Route.rock_types) climbing_outdoor_type = QEnumArray('crtyp', model_field=Route.climbing_outdoor_type) slackline_type = QEnum('sltyp', model_field=Route.slackline_type) FIELDS = [ 'activities', 'elevation_min', 'elevation_max', 'height_diff_up', 'height_diff_down', 'route_length', 'difficulties_height', 'height_diff_access', 'height_diff_difficulties', 'route_types', 'orientations', 'glacier_gear', 'configuration', 'mtb_length_asphalt', 'mtb_length_trail', 'mtb_height_diff_portages', 'rock_types', 'climbing_outdoor_type', 'slackline_type' ] ENUM_RANGE_FIELDS = [ 'durations', 'ski_rating', 'ski_exposition', 'labande_ski_rating', 'labande_global_rating', 'global_rating', 'engagement_rating', 'risk_rating', 'equipment_rating', 'ice_rating', 'mixed_rating', 'exposition_rock_rating', 'rock_free_rating', 'rock_required_rating', 'aid_rating', 'via_ferrata_rating', 'hiking_rating', 'hiking_mtb_exposition', 'snowshoe_rating', 'mtb_up_rating', 'mtb_down_rating', ] @staticmethod def to_search_document(document, index): search_document = SearchDocument.to_search_document(document, index) if document.redirects_to: return search_document SearchDocument.copy_fields(search_document, document, SearchRoute.FIELDS) SearchDocument.copy_enum_range_fields(search_document, document, SearchRoute.ENUM_RANGE_FIELDS, SearchRoute) for locale in document.locales: search_document['title_' + locale.lang] = \ get_title(locale.title, locale.title_prefix) if document.associated_waypoints_ids: # add the document ids of associated waypoints and of the parent # and grand-parents of these waypoints search_document['waypoints'] = \ document.associated_waypoints_ids.waypoint_ids if document.associated_users_ids: # add the document ids of associated users search_document['users'] = \ document.associated_users_ids.user_ids return search_document
class SearchWaypoint(SearchDocument): class Meta(BaseMeta): doc_type = WAYPOINT_TYPE elevation = QInteger('walt', range=True) prominence = QInteger('prom', range=True) waypoint_type = QEnum('wtyp', model_field=Waypoint.waypoint_type) rock_types = QEnumArray('wrock', model_field=Waypoint.rock_types) orientations = QEnumArray('wfac', model_field=Waypoint.orientations) best_periods = QEnumArray('period', model_field=Waypoint.best_periods) lift_access = QBoolean('plift', is_bool=True) custodianship = QEnum('hsta', model_field=Waypoint.custodianship) climbing_styles = QEnumArray('tcsty', model_field=Waypoint.climbing_styles) access_time = QEnumRange('tappt', model_field=Waypoint.access_time, enum_mapper=sortable_access_times) climbing_rating_max = QEnumRange('tmaxr', model_field=Waypoint.climbing_rating_max, enum_mapper=sortable_climbing_ratings) climbing_rating_min = QEnumRange('tminr', model_field=Waypoint.climbing_rating_min, enum_mapper=sortable_climbing_ratings) climbing_rating_median = QEnumRange( 'tmedr', model_field=Waypoint.climbing_rating_median, enum_mapper=sortable_climbing_ratings) height_max = QInteger('tmaxh', range=True) height_min = QInteger('tminh', range=True) height_median = QInteger('tmedh', range=True) routes_quantity = QInteger('rqua', range=True) children_proof = QEnum('chil', model_field=Waypoint.children_proof) rain_proof = QEnum('rain', model_field=Waypoint.rain_proof) climbing_outdoor_types = QEnumArray( 'ctout', model_field=Waypoint.climbing_outdoor_types) climbing_indoor_types = QEnumArray( 'ctin', model_field=Waypoint.climbing_indoor_types) paragliding_rating = QEnumRange('pgrat', model_field=Waypoint.paragliding_rating, enum_mapper=sortable_paragliding_ratings) exposition_rating = QEnumRange('pglexp', model_field=Waypoint.exposition_rating, enum_mapper=sortable_exposition_ratings) length = QInteger('len', range=True) weather_station_types = QEnumArray( 'whtyp', model_field=Waypoint.weather_station_types) capacity = QInteger('hucap', range=True) capacity_staffed = QInteger('hscap', range=True) equipment_ratings = QEnumRange('anchq', model_field=Waypoint.equipment_ratings, enum_mapper=sortable_equipment_ratings) public_transportation_types = QEnumArray( 'tpty', model_field=Waypoint.public_transportation_types) public_transportation_rating = QEnum( 'tp', model_field=Waypoint.public_transportation_rating) snow_clearance_rating = QEnum('psnow', model_field=Waypoint.snow_clearance_rating) product_types = QEnumArray('ftyp', model_field=Waypoint.product_types) FIELDS = [ 'elevation', 'prominence', 'waypoint_type', 'rock_types', 'orientations', 'climbing_outdoor_types', 'climbing_indoor_types', 'best_periods', 'lift_access', 'custodianship', 'climbing_styles', 'height_max', 'height_min', 'height_median', 'routes_quantity', 'children_proof', 'rain_proof', 'length', 'weather_station_types', 'capacity', 'capacity_staffed', 'public_transportation_types', 'public_transportation_rating', 'snow_clearance_rating', 'product_types' ] ENUM_RANGE_FIELDS = [ 'access_time', 'climbing_rating_max', 'climbing_rating_min', 'climbing_rating_median', 'paragliding_rating', 'exposition_rating', 'equipment_ratings' ] @staticmethod def to_search_document(document, index): search_document = SearchDocument.to_search_document(document, index) if document.redirects_to: return search_document SearchDocument.copy_fields(search_document, document, SearchWaypoint.FIELDS) SearchDocument.copy_enum_range_fields(search_document, document, SearchWaypoint.ENUM_RANGE_FIELDS, SearchWaypoint) return search_document
class SearchDocument(DocType): """The base ElasticSearch mapping for documents. Each document type has its own specific mapping. We are using the "one language per field" strategy, for example for the title field we have a field for each language: title_en, title_fr, ... See also: https://www.elastic.co/guide/en/elasticsearch/guide/current/one-lang-fields.html For the search a different analyzer is used than for the indexing. This is because the index analyzer uses n-grams, while the search words should not be cut into n-gram tokens. See also: https://www.elastic.co/guide/en/elasticsearch/guide/current/_index_time_search_as_you_type.html """ class Meta(BaseMeta): pass id = Long() doc_type = Enum() quality = QEnum('qa', model_field=Document.quality) available_locales = QEnumArray('l', enum=default_langs) geom = GeoPoint() # array of area ids areas = QLong('a', is_id=True) # fr title_fr = String(analyzer='index_french', search_analyzer='search_french') summary_fr = String(analyzer='index_french', search_analyzer='search_french') description_fr = String(analyzer='index_french', search_analyzer='search_french') # it title_it = String(analyzer='index_italian', search_analyzer='search_italian') summary_it = String(analyzer='index_italian', search_analyzer='search_italian') description_it = String(analyzer='index_italian', search_analyzer='search_italian') # de title_de = String(analyzer='index_german', search_analyzer='search_german') summary_de = String(analyzer='index_german', search_analyzer='search_german') description_de = String(analyzer='index_german', search_analyzer='search_german') # en title_en = String(analyzer='index_english', search_analyzer='search_english') summary_en = String(analyzer='index_english', search_analyzer='search_english') description_en = String(analyzer='index_english', search_analyzer='search_english') # es title_es = String(analyzer='index_spanish', search_analyzer='search_spanish') summary_es = String(analyzer='index_spanish', search_analyzer='search_spanish') description_es = String(analyzer='index_spanish', search_analyzer='search_spanish') # ca title_ca = String(analyzer='index_catalan', search_analyzer='search_catalan') summary_ca = String(analyzer='index_catalan', search_analyzer='search_catalan') description_ca = String(analyzer='index_catalan', search_analyzer='search_catalan') # eu title_eu = String(analyzer='index_basque', search_analyzer='search_basque') summary_eu = String(analyzer='index_basque', search_analyzer='search_basque') description_eu = String(analyzer='index_basque', search_analyzer='search_basque') @staticmethod def to_search_document(document, index, include_areas=True): search_document = { '_index': index, '_id': document.document_id, '_type': document.type, 'id': document.document_id } if document.redirects_to: # remove merged documents from the index search_document['_op_type'] = 'delete' else: search_document['_op_type'] = 'index' search_document['doc_type'] = document.type available_locales = [] for locale in document.locales: available_locales.append(locale.lang) search_document['title_' + locale.lang] = locale.title search_document['summary_' + locale.lang] = \ strip_bbcodes(locale.summary) search_document['description_' + locale.lang] = \ strip_bbcodes(locale.description) search_document['available_locales'] = available_locales if document.geometry: search_document['geom'] = SearchDocument.get_geometry( document.geometry) areas = [] if include_areas: for area in document._areas: areas.append(area.document_id) search_document['areas'] = areas return search_document @staticmethod def get_geometry(geometry): if geometry.lon_lat: geojson = json.loads(geometry.lon_lat) return geojson['coordinates'] else: return None @staticmethod def copy_fields(search_document, document, fields): for field in fields: search_document[field] = getattr(document, field)
class SearchRoute(SearchDocument): class Meta(BaseMeta): doc_type = ROUTE_TYPE activities = QEnumArray('act', model_field=Route.activities) elevation_min = QInteger('rmina', range=True) elevation_max = QInteger('rmaxa', range=True) height_diff_up = QInteger('hdif', range=True) height_diff_down = QInteger('ddif', range=True) route_length = QInteger('rlen', range=True) difficulties_height = QInteger('ralt ', range=True) height_diff_access = QInteger('rappr', range=True) height_diff_difficulties = QInteger('dhei ', range=True) route_types = QEnumArray('rtyp', model_field=Route.route_types) orientations = QEnumArray('fac', model_field=Route.orientations) durations = QEnumArray('time', model_field=Route.durations) glacier_gear = QEnum('glac', model_field=Route.glacier_gear) configuration = QEnumArray('conf', model_field=Route.configuration) ski_rating = QEnum('trat', model_field=Route.ski_rating) ski_exposition = QEnum('sexpo', model_field=Route.ski_exposition) labande_ski_rating = QEnum('srat', model_field=Route.labande_ski_rating) labande_global_rating = QEnum('lrat', model_field=Route.labande_global_rating) global_rating = QEnum('grat', model_field=Route.global_rating) engagement_rating = QEnum('erat', model_field=Route.engagement_rating) risk_rating = QEnum('orrat', model_field=Route.risk_rating) equipment_rating = QEnum('prat', model_field=Route.equipment_rating) ice_rating = QEnum('irat', model_field=Route.ice_rating) mixed_rating = QEnum('mrat', model_field=Route.mixed_rating) exposition_rock_rating = QEnum('rexpo', model_field=Route.exposition_rock_rating) rock_free_rating = QEnum('frat', model_field=Route.rock_free_rating) rock_required_rating = QEnum('rrat', model_field=Route.rock_required_rating) aid_rating = QEnum('arat', model_field=Route.aid_rating) via_ferrata_rating = QEnum('krat', model_field=Route.via_ferrata_rating) hiking_rating = QEnum('hrat', model_field=Route.hiking_rating) hiking_mtb_exposition = QEnum('hexpo', model_field=Route.hiking_mtb_exposition) snowshoe_rating = QEnum('wrat', model_field=Route.snowshoe_rating) mtb_up_rating = QEnum('mbur', model_field=Route.mtb_up_rating) mtb_down_rating = QEnum('mbdr', model_field=Route.mtb_down_rating) mtb_length_asphalt = QInteger('mbroad', range=True) mtb_length_trail = QInteger('mbtrack', range=True) mtb_height_diff_portages = QInteger('mbpush', range=True) rock_types = QEnumArray('rock', model_field=Route.rock_types) climbing_outdoor_type = QEnumArray('crtyp', model_field=Route.climbing_outdoor_type) FIELDS = [ 'activities', 'elevation_min', 'elevation_max', 'height_diff_up', 'height_diff_down', 'route_length', 'difficulties_height', 'height_diff_access', 'height_diff_difficulties', 'route_types', 'orientations', 'durations', 'glacier_gear', 'configuration', 'ski_rating', 'ski_exposition', 'labande_ski_rating', 'labande_global_rating', 'global_rating', 'engagement_rating', 'risk_rating', 'equipment_rating', 'ice_rating', 'mixed_rating', 'exposition_rock_rating', 'rock_free_rating', 'rock_required_rating', 'aid_rating', 'via_ferrata_rating', 'hiking_rating', 'hiking_mtb_exposition', 'snowshoe_rating', 'mtb_up_rating', 'mtb_down_rating', 'mtb_length_asphalt', 'mtb_length_trail', 'mtb_height_diff_portages', 'rock_types', 'climbing_outdoor_type' ] @staticmethod def to_search_document(document, index): search_document = SearchDocument.to_search_document(document, index) if document.redirects_to: return search_document SearchDocument.copy_fields(search_document, document, SearchRoute.FIELDS) for locale in document.locales: search_document['title_' + locale.lang] = \ get_title(locale.title, locale.title_prefix) return search_document