1+ #!/usr/bin/env python3
2+
3+ import os
4+ import sys
5+ import django
6+ import time
7+ import requests
8+ from statistics import mean
9+
10+ # Django setup
11+ os .environ .setdefault ('DJANGO_SETTINGS_MODULE' , 'server.settings' )
12+ sys .path .append ('/Users/moody/open5e-api' )
13+ sys .path .append (os .path .dirname (os .path .dirname (os .path .abspath (__file__ )))) # Add parent directory
14+ django .setup ()
15+
16+ def time_search (query , params = None ):
17+ """Time a search request and return timing + result info."""
18+ url = "http://127.0.0.1:8000/v2/search/"
19+ search_params = {"query" : query }
20+ if params :
21+ search_params .update (params )
22+
23+ start_time = time .time ()
24+ response = requests .get (url , params = search_params )
25+ end_time = time .time ()
26+
27+ if response .status_code != 200 :
28+ return None , f"Error: { response .status_code } "
29+
30+ data = response .json ()
31+ timing = (end_time - start_time ) * 1000 # Convert to milliseconds
32+
33+ # Just get the total count
34+ total_results = data .get ('count' , 0 )
35+ metadata = data .get ('search_metadata' , {})
36+ exact_matches = metadata .get ('exact_matches' , False )
37+
38+ return timing , {
39+ 'total_results' : total_results ,
40+ 'exact_matches' : exact_matches
41+ }
42+
43+ def run_performance_test ():
44+ """Run simplified performance comparison of search modes."""
45+
46+ # Test queries covering different scenarios
47+ test_queries = [
48+ "fire" , # Common term, many exact matches
49+ "sword" , # Common term, many exact matches
50+ "heal" , # Common term, some matches
51+ "dragon" , # Common term, many matches
52+ "fireball" , # Specific spell, exact matches
53+ "teleport" , # Specific spell, exact matches
54+ "magic weapon" , # Multi-word, exact matches
55+ "chromatic orb" , # Specific spell, few matches
56+ "firbal" , # Typo, fuzzy fallback
57+ "dragn" , # Typo, fuzzy fallback
58+ ]
59+
60+ results_table = []
61+
62+ print ("Search Mode Performance Comparison" )
63+ print ("=" * 80 )
64+ print ("Testing: Default (exact + fuzzy fallback) vs Fuzzy-strict vs Vector-strict" )
65+ print ()
66+
67+ for query in test_queries :
68+ print (f"Testing '{ query } '..." )
69+
70+ # Test Default mode (exact + fuzzy fallback if needed)
71+ default_times = []
72+ default_info = None
73+ for _ in range (3 ):
74+ timing , info = time_search (query )
75+ if timing is not None :
76+ default_times .append (timing )
77+ if default_info is None :
78+ default_info = info
79+
80+ # Test Fuzzy-strict mode
81+ fuzzy_times = []
82+ fuzzy_info = None
83+ for _ in range (3 ):
84+ timing , info = time_search (query , {"strict" : "true" , "fuzzy" : "true" })
85+ if timing is not None :
86+ fuzzy_times .append (timing )
87+ if fuzzy_info is None :
88+ fuzzy_info = info
89+
90+ # Test Vector-strict mode
91+ vector_times = []
92+ vector_info = None
93+ for _ in range (3 ):
94+ timing , info = time_search (query , {"strict" : "true" , "vector" : "true" })
95+ if timing is not None :
96+ vector_times .append (timing )
97+ if vector_info is None :
98+ vector_info = info
99+
100+ # Calculate averages and format results
101+ default_avg = mean (default_times ) if default_times else 0
102+ fuzzy_avg = mean (fuzzy_times ) if fuzzy_times else 0
103+ vector_avg = mean (vector_times ) if vector_times else 0
104+
105+ # Format result information
106+ def format_results (info ):
107+ if not info :
108+ return "Error"
109+ total = info ['total_results' ]
110+ return f"{ total } "
111+
112+ results_table .append ({
113+ 'query' : query ,
114+ 'default_time' : default_avg ,
115+ 'default_results' : format_results (default_info ),
116+ 'fuzzy_time' : fuzzy_avg ,
117+ 'fuzzy_results' : format_results (fuzzy_info ),
118+ 'vector_time' : vector_avg ,
119+ 'vector_results' : format_results (vector_info )
120+ })
121+
122+ # Output markdown table
123+ print ("\n Results (Markdown Table):" )
124+ print ("=" * 80 )
125+ print ("| Query | Default Mode | | Fuzzy-Strict | | Vector-Strict | |" )
126+ print ("|-------|-------------|---|-------------|---|-------------|---|" )
127+ print ("| | Time (ms) | Results | Time (ms) | Results | Time (ms) | Results |" )
128+
129+ for row in results_table :
130+ print (f"| { row ['query' ]} | { row ['default_time' ]:.1f} | { row ['default_results' ]} | "
131+ f"{ row ['fuzzy_time' ]:.1f} | { row ['fuzzy_results' ]} | "
132+ f"{ row ['vector_time' ]:.1f} | { row ['vector_results' ]} |" )
133+
134+ print ()
135+ print ("Legend:" )
136+ print ("- Default Mode: Runs exact search, falls back to fuzzy if exact finds 0 results" )
137+ print ("- Fuzzy-Strict: Only fuzzy search" )
138+ print ("- Vector-Strict: Only vector search" )
139+ print ("- Results: Total matches found across all pages (API returns 50 per page)" )
140+
141+ if __name__ == "__main__" :
142+ print ("Starting simplified search performance comparison..." )
143+ print ("Make sure the Django dev server is running on http://127.0.0.1:8000" )
144+ print ()
145+
146+ try :
147+ # Quick connectivity test
148+ response = requests .get ("http://127.0.0.1:8000/v2/search/" , params = {"query" : "test" })
149+ if response .status_code != 200 :
150+ print (f"Server connectivity issue: { response .status_code } " )
151+ sys .exit (1 )
152+ except requests .exceptions .ConnectionError :
153+ print ("Cannot connect to server. Please start the Django dev server first:" )
154+ print ("python manage.py runserver" )
155+ sys .exit (1 )
156+
157+ run_performance_test ()
0 commit comments