Trace query response performance and display timings in verbose mode

This commit is contained in:
Debanjum Singh Solanky 2022-07-26 21:03:53 +04:00
parent d8efcd559f
commit f094c86204
3 changed files with 64 additions and 14 deletions

View file

@ -1,5 +1,6 @@
# Standard Packages # Standard Packages
import sys, json, yaml, os import sys, json, yaml, os
import time
from typing import Optional from typing import Optional
# External Packages # External Packages
@ -66,50 +67,74 @@ def search(q: str, n: Optional[int] = 5, t: Optional[SearchType] = None):
device = torch.device("cuda:0") if torch.cuda.is_available() else torch.device("cpu") device = torch.device("cuda:0") if torch.cuda.is_available() else torch.device("cpu")
user_query = q user_query = q
results_count = n results_count = n
results = {}
if (t == SearchType.Org or t == None) and model.orgmode_search: if (t == SearchType.Org or t == None) and model.orgmode_search:
# query org-mode notes # query org-mode notes
hits, entries = text_search.query(user_query, model.orgmode_search, device=device, filters=[explicit_filter, date_filter]) query_start = time.time()
hits, entries = text_search.query(user_query, model.orgmode_search, device=device, filters=[explicit_filter, date_filter], verbose=verbose)
query_end = time.time()
# collate and return results # collate and return results
return text_search.collate_results(hits, entries, results_count) collate_start = time.time()
results = text_search.collate_results(hits, entries, results_count)
collate_end = time.time()
if (t == SearchType.Music or t == None) and model.music_search: if (t == SearchType.Music or t == None) and model.music_search:
# query music library # query music library
hits, entries = text_search.query(user_query, model.music_search, device=device, filters=[explicit_filter, date_filter]) query_start = time.time()
hits, entries = text_search.query(user_query, model.music_search, device=device, filters=[explicit_filter, date_filter], verbose=verbose)
query_end = time.time()
# collate and return results # collate and return results
return text_search.collate_results(hits, entries, results_count) collate_start = time.time()
results = text_search.collate_results(hits, entries, results_count)
collate_end = time.time()
if (t == SearchType.Markdown or t == None) and model.orgmode_search: if (t == SearchType.Markdown or t == None) and model.orgmode_search:
# query markdown files # query markdown files
hits, entries = text_search.query(user_query, model.markdown_search, device=device, filters=[explicit_filter, date_filter]) query_start = time.time()
hits, entries = text_search.query(user_query, model.markdown_search, device=device, filters=[explicit_filter, date_filter], verbose=verbose)
query_end = time.time()
# collate and return results # collate and return results
return text_search.collate_results(hits, entries, results_count) collate_start = time.time()
results = text_search.collate_results(hits, entries, results_count)
collate_end = time.time()
if (t == SearchType.Ledger or t == None) and model.ledger_search: if (t == SearchType.Ledger or t == None) and model.ledger_search:
# query transactions # query transactions
hits, entries = text_search.query(user_query, model.ledger_search, filters=[explicit_filter, date_filter]) query_start = time.time()
hits, entries = text_search.query(user_query, model.ledger_search, filters=[explicit_filter, date_filter], verbose=verbose)
query_end = time.time()
# collate and return results # collate and return results
return text_search.collate_results(hits, entries, results_count) collate_start = time.time()
results = text_search.collate_results(hits, entries, results_count)
collate_end = time.time()
if (t == SearchType.Image or t == None) and model.image_search: if (t == SearchType.Image or t == None) and model.image_search:
# query images # query images
hits = image_search.query(user_query, results_count, model.image_search) query_start = time.time()
hits = image_search.query(user_query, results_count, model.image_search, verbose=verbose)
output_directory = f'{os.getcwd()}/{web_directory}' output_directory = f'{os.getcwd()}/{web_directory}'
query_end = time.time()
# collate and return results # collate and return results
return image_search.collate_results( collate_start = time.time()
results = image_search.collate_results(
hits, hits,
image_names=model.image_search.image_names, image_names=model.image_search.image_names,
output_directory=output_directory, output_directory=output_directory,
static_files_url='/static', static_files_url='/static',
count=results_count) count=results_count)
collate_end = time.time()
else: if verbose > 1:
return {} print(f"Query took {query_end - query_start:.3f} seconds")
print(f"Collating results took {collate_end - collate_start:.3f} seconds")
return results
@app.get('/reload') @app.get('/reload')

View file

@ -82,7 +82,7 @@ def convert_org_entries_to_jsonl(entries, verbose=0):
continue continue
entry_dict["compiled"] = f'{entry.Heading()}.' entry_dict["compiled"] = f'{entry.Heading()}.'
if verbose > 1: if verbose > 2:
print(f"Title: {entry.Heading()}") print(f"Title: {entry.Heading()}")
if entry.Tags(): if entry.Tags():

View file

@ -2,6 +2,7 @@
import argparse import argparse
import pathlib import pathlib
from copy import deepcopy from copy import deepcopy
import time
# External Packages # External Packages
import torch import torch
@ -62,38 +63,62 @@ def compute_embeddings(entries, bi_encoder, embeddings_file, regenerate=False, d
return corpus_embeddings return corpus_embeddings
def query(raw_query: str, model: TextSearchModel, device='cpu', filters: list = []): def query(raw_query: str, model: TextSearchModel, device='cpu', filters: list = [], verbose=0):
"Search for entries that answer the query" "Search for entries that answer the query"
# Copy original embeddings, entries to filter them for query # Copy original embeddings, entries to filter them for query
start = time.time()
query = raw_query query = raw_query
corpus_embeddings = deepcopy(model.corpus_embeddings) corpus_embeddings = deepcopy(model.corpus_embeddings)
entries = deepcopy(model.entries) entries = deepcopy(model.entries)
end = time.time()
if verbose > 1:
print(f"Copy Time: {end - start:.3f} seconds")
# Filter query, entries and embeddings before semantic search # Filter query, entries and embeddings before semantic search
start = time.time()
for filter in filters: for filter in filters:
query, entries, corpus_embeddings = filter(query, entries, corpus_embeddings) query, entries, corpus_embeddings = filter(query, entries, corpus_embeddings)
if entries is None or len(entries) == 0: if entries is None or len(entries) == 0:
return [], [] return [], []
end = time.time()
if verbose > 1:
print(f"Filter Time: {end - start:.3f} seconds")
# Encode the query using the bi-encoder # Encode the query using the bi-encoder
start = time.time()
question_embedding = model.bi_encoder.encode([query], convert_to_tensor=True) question_embedding = model.bi_encoder.encode([query], convert_to_tensor=True)
question_embedding.to(device) question_embedding.to(device)
question_embedding = util.normalize_embeddings(question_embedding) question_embedding = util.normalize_embeddings(question_embedding)
end = time.time()
if verbose > 1:
print(f"Query Encode Time: {end - start:.3f} seconds")
# Find relevant entries for the query # Find relevant entries for the query
start = time.time()
hits = util.semantic_search(question_embedding, corpus_embeddings, top_k=model.top_k, score_function=util.dot_score)[0] hits = util.semantic_search(question_embedding, corpus_embeddings, top_k=model.top_k, score_function=util.dot_score)[0]
end = time.time()
if verbose > 1:
print(f"Search Time: {end - start:.3f} seconds")
# Score all retrieved entries using the cross-encoder # Score all retrieved entries using the cross-encoder
start = time.time()
cross_inp = [[query, entries[hit['corpus_id']]['compiled']] for hit in hits] cross_inp = [[query, entries[hit['corpus_id']]['compiled']] for hit in hits]
cross_scores = model.cross_encoder.predict(cross_inp) cross_scores = model.cross_encoder.predict(cross_inp)
end = time.time()
if verbose > 1:
print(f"Cross-Encoder Predict Time: {end - start:.3f} seconds")
# Store cross-encoder scores in results dictionary for ranking # Store cross-encoder scores in results dictionary for ranking
for idx in range(len(cross_scores)): for idx in range(len(cross_scores)):
hits[idx]['cross-score'] = cross_scores[idx] hits[idx]['cross-score'] = cross_scores[idx]
# Order results by cross-encoder score followed by bi-encoder score # Order results by cross-encoder score followed by bi-encoder score
start = time.time()
hits.sort(key=lambda x: x['score'], reverse=True) # sort by bi-encoder score hits.sort(key=lambda x: x['score'], reverse=True) # sort by bi-encoder score
hits.sort(key=lambda x: x['cross-score'], reverse=True) # sort by cross-encoder score hits.sort(key=lambda x: x['cross-score'], reverse=True) # sort by cross-encoder score
end = time.time()
if verbose > 1:
print(f"Rank Time: {end - start:.3f} seconds")
return hits, entries return hits, entries