(db: str, p_str: str, g_str: str, plug_value: bool, keep_distinct: bool, progress_bar_for_each_datapoint: bool, debug=False)
| 184 | # the meaning of each auxillary argument can be seen in the parser definition in evaluation.py |
| 185 | # @timeout_decorator.timeout(600) |
| 186 | def eval_exec_match(db: str, p_str: str, g_str: str, plug_value: bool, keep_distinct: bool, progress_bar_for_each_datapoint: bool, debug=False) -> int: |
| 187 | # post-process the prediction. |
| 188 | # e.g. removing spaces between ">" and "=" |
| 189 | p_str, g_str = postprocess(p_str), postprocess(g_str) |
| 190 | if not keep_distinct: |
| 191 | p_str = remove_distinct(p_str) |
| 192 | g_str = remove_distinct(g_str) |
| 193 | |
| 194 | # we decide whether two denotations are equivalent based on "bag semantics" |
| 195 | # https://courses.cs.washington.edu/courses/cse444/10sp/lectures/lecture16.pdf |
| 196 | # if there is order by in query, then we assume order of the rows matter |
| 197 | # order by might also be used to find the max/min instead of sorting, |
| 198 | # but in that case the result mostly only contains one row and hence order_matters does not make a difference |
| 199 | order_matters = 'order by' in g_str.lower() |
| 200 | |
| 201 | # find all databases in the same directory |
| 202 | db_dir = os.path.dirname(db) |
| 203 | db_paths = [os.path.join(db_dir, basename) for basename in os.listdir(db_dir) if '.sqlite' in basename] |
| 204 | |
| 205 | preds = [p_str] |
| 206 | # if plug in value (i.e. we do not consider value prediction correctness) |
| 207 | # enumerate all ways to plug in values in the gold query to the model predictions |
| 208 | # otherwise, we only evaluate the predicted query with its own value prediction |
| 209 | if plug_value: |
| 210 | _, preds = get_all_preds_for_execution(g_str, p_str) |
| 211 | # we did not add this line in our EMNLP work |
| 212 | # this reduces "false negatives" when value is substituted |
| 213 | preds = chain([p_str], preds) |
| 214 | |
| 215 | for pred in preds: |
| 216 | |
| 217 | pred_passes = 1 |
| 218 | # compare the gold and predicted denotations on each database in the directory |
| 219 | # wrap with progress bar if required |
| 220 | if progress_bar_for_each_datapoint: |
| 221 | ranger = tqdm.tqdm(db_paths) |
| 222 | else: |
| 223 | ranger = db_paths |
| 224 | |
| 225 | for db_path in ranger: |
| 226 | g_flag, g_denotation = asyncio.run(exec_on_db(db_path, g_str)) |
| 227 | |
| 228 | # we should expect the gold to be succesfully executed on the database |
| 229 | # assert g_flag != 'exception', 'gold query %s has error on database file %s' % (g_str, db_path) |
| 230 | p_flag, p_denotation = asyncio.run(exec_on_db(db_path, pred)) |
| 231 | if debug: |
| 232 | print(f"ground_truth result: {g_denotation}") |
| 233 | print(f"prediction result: {p_denotation}") |
| 234 | |
| 235 | # wrong if execution fails |
| 236 | if p_flag == 'exception': |
| 237 | pred_passes = 0 |
| 238 | |
| 239 | # if denotations are not equivalent, the prediction must be wrong |
| 240 | elif not result_eq(g_denotation, p_denotation, order_matters=order_matters): |
| 241 | pred_passes = 0 |
| 242 | if pred_passes == 0: |
| 243 | break |
no test coverage detected