@@ -164,6 +164,32 @@ def _reasonable_release_tags_match(control: set[TagValue], experimental: set[Tag
164164 )
165165
166166
167+ def _reasonable_group_list_tag_value_match (
168+ control : dict [int , GroupTagValue ],
169+ experimental : dict [int , GroupTagValue ],
170+ ) -> bool :
171+ if not set (experimental .keys ()).issubset (set (control .keys ())):
172+ return False
173+ for group_id in experimental :
174+ ctrl = control [group_id ]
175+ exp = experimental [group_id ]
176+ if exp .times_seen > ctrl .times_seen :
177+ return False
178+ if (
179+ exp .first_seen is not None
180+ and ctrl .first_seen is not None
181+ and exp .first_seen < ctrl .first_seen
182+ ):
183+ return False
184+ if (
185+ exp .last_seen is not None
186+ and ctrl .last_seen is not None
187+ and exp .last_seen > ctrl .last_seen
188+ ):
189+ return False
190+ return True
191+
192+
167193class _OptimizeKwargs (TypedDict , total = False ):
168194 turbo : bool
169195 sample : int
@@ -825,7 +851,7 @@ def get_group_list_tag_value(
825851 value ,
826852 tenant_ids = None ,
827853 ):
828- return self .__get_group_list_tag_value (
854+ snuba_result = self .__get_group_list_tag_value (
829855 project_ids ,
830856 group_id_list ,
831857 environment_ids ,
@@ -834,9 +860,38 @@ def get_group_list_tag_value(
834860 Dataset .Events ,
835861 [DEFAULT_TYPE_CONDITION ],
836862 [],
837- "tagstore.get_group_list_tag_value" ,
863+ Referrer . TAGSTORE_GET_GROUP_LIST_TAG_VALUE . value ,
838864 tenant_ids = tenant_ids ,
839865 )
866+ result = snuba_result
867+
868+ callsite = "SnubaTagStorage::get_group_list_tag_value"
869+ if EAPOccurrencesComparator .should_check_experiment (callsite ):
870+ eap_result = self ._eap_get_group_list_tag_value (
871+ project_ids ,
872+ group_id_list ,
873+ environment_ids ,
874+ key ,
875+ value ,
876+ referrer = Referrer .TAGSTORE_GET_GROUP_LIST_TAG_VALUE .value ,
877+ occurrence_category = OccurrenceCategory .ERROR ,
878+ )
879+ result = EAPOccurrencesComparator .check_and_choose (
880+ control_data = snuba_result ,
881+ experimental_data = eap_result ,
882+ callsite = callsite ,
883+ is_experimental_data_a_null_result = len (eap_result ) == 0 ,
884+ reasonable_match_comparator = _reasonable_group_list_tag_value_match ,
885+ debug_context = {
886+ "project_ids" : list (project_ids ),
887+ "group_ids" : list (group_id_list ),
888+ "environment_ids" : list (environment_ids ) if environment_ids else None ,
889+ "key" : key ,
890+ "value" : value ,
891+ },
892+ )
893+
894+ return result
840895
841896 def get_generic_group_list_tag_value (
842897 self ,
@@ -890,12 +945,137 @@ def get_generic_group_list_tag_value(
890945 result_snql ["data" ], ["group_id" ], ["times_seen" , "first_seen" , "last_seen" ]
891946 )
892947
893- return {
948+ snuba_result = {
894949 group_id : GroupTagValue (
895950 group_id = group_id , key = key , value = value , ** fix_tag_value_data (data )
896951 )
897952 for group_id , data in nested_groups .items ()
898953 }
954+ result = snuba_result
955+
956+ callsite = "SnubaTagStorage::get_generic_group_list_tag_value"
957+ if EAPOccurrencesComparator .should_check_experiment (callsite ):
958+ eap_result = self ._eap_get_group_list_tag_value (
959+ project_ids ,
960+ group_id_list ,
961+ environment_ids ,
962+ key ,
963+ value ,
964+ referrer = Referrer .TAGSTORE_GET_GENERIC_GROUP_LIST_TAG_VALUE .value ,
965+ occurrence_category = OccurrenceCategory .ISSUE_PLATFORM ,
966+ )
967+ result = EAPOccurrencesComparator .check_and_choose (
968+ control_data = snuba_result ,
969+ experimental_data = eap_result ,
970+ callsite = callsite ,
971+ is_experimental_data_a_null_result = len (eap_result ) == 0 ,
972+ reasonable_match_comparator = _reasonable_group_list_tag_value_match ,
973+ debug_context = {
974+ "project_ids" : list (project_ids ),
975+ "group_ids" : list (group_id_list ),
976+ "environment_ids" : list (environment_ids ) if environment_ids else None ,
977+ "key" : key ,
978+ "value" : value ,
979+ },
980+ )
981+
982+ return result
983+
984+ def _eap_get_group_list_tag_value (
985+ self ,
986+ project_ids : Sequence [int ],
987+ group_id_list : Sequence [int ],
988+ environment_ids : Sequence [int ] | None ,
989+ key : str ,
990+ value : str ,
991+ referrer : str ,
992+ occurrence_category : OccurrenceCategory ,
993+ ) -> dict [int , GroupTagValue ]:
994+ organization_id = get_organization_id_from_project_ids (project_ids )
995+
996+ now = datetime .now (tz = timezone .utc )
997+ resolved_start = now - timedelta (days = 90 )
998+ resolved_end = now
999+
1000+ try :
1001+ organization = Organization .objects .get_from_cache (id = organization_id )
1002+ except Organization .DoesNotExist :
1003+ return {}
1004+
1005+ projects = list (Project .objects .filter (id__in = project_ids , organization_id = organization_id ))
1006+ if not projects :
1007+ return {}
1008+
1009+ environments = (
1010+ list (Environment .objects .filter (id__in = environment_ids )) if environment_ids else []
1011+ )
1012+
1013+ group_id_filter = f"group_id:[{ ',' .join (str (gid ) for gid in group_id_list )} ]"
1014+ tag_filter = build_escaped_term_filter (key , [str (value )])
1015+ query_string = f"{ group_id_filter } { tag_filter } "
1016+
1017+ snuba_params = SnubaParams (
1018+ start = resolved_start ,
1019+ end = resolved_end ,
1020+ organization = organization ,
1021+ projects = projects ,
1022+ environments = environments ,
1023+ )
1024+
1025+ try :
1026+ result = Occurrences .run_table_query (
1027+ params = snuba_params ,
1028+ query_string = query_string ,
1029+ selected_columns = ["group_id" , "count()" , "min(timestamp)" , "last_seen()" ],
1030+ orderby = None ,
1031+ offset = 0 ,
1032+ limit = len (group_id_list ),
1033+ referrer = referrer ,
1034+ config = SearchResolverConfig (),
1035+ occurrence_category = occurrence_category ,
1036+ )
1037+
1038+ output : dict [int , GroupTagValue ] = {}
1039+ for row in result .get ("data" , []):
1040+ group_id = row .get ("group_id" )
1041+ if group_id is None :
1042+ continue
1043+ first_seen_raw = row .get ("min(timestamp)" )
1044+ last_seen_raw = row .get ("last_seen()" )
1045+ output [int (group_id )] = GroupTagValue (
1046+ group_id = int (group_id ),
1047+ key = key ,
1048+ value = value ,
1049+ times_seen = int (row .get ("count()" , 0 )),
1050+ first_seen = (
1051+ parse_datetime (datetime_processor (first_seen_raw )).replace (
1052+ tzinfo = timezone .utc
1053+ )
1054+ if first_seen_raw is not None
1055+ else None
1056+ ),
1057+ last_seen = (
1058+ parse_datetime (datetime_processor (last_seen_raw )).replace (
1059+ tzinfo = timezone .utc
1060+ )
1061+ if last_seen_raw is not None
1062+ else None
1063+ ),
1064+ )
1065+ return output
1066+ except Exception :
1067+ logger .exception (
1068+ "EAP get_group_list_tag_value query failed" ,
1069+ extra = {
1070+ "organization_id" : organization_id ,
1071+ "project_ids" : list (project_ids ),
1072+ "group_ids" : list (group_id_list ),
1073+ "key" : key ,
1074+ "value" : value ,
1075+ "occurrence_category" : occurrence_category .value ,
1076+ },
1077+ )
1078+ return {}
8991079
9001080 def apply_group_filters (self , group : Group | None , filters : MutableMapping [str , Sequence [Any ]]):
9011081 dataset = Dataset .Events
0 commit comments