@@ -23,6 +23,8 @@ export class KnowledgeQuerier {
2323 private cacheHits = 0 ;
2424 private cacheMisses = 0 ;
2525 private comparisonCount = 0 ;
26+ private queryPatternCounts = new Map < string , number > ( ) ;
27+ private slowQueryCount = 0 ;
2628 private readonly cacheTtlMs : number ;
2729
2830 constructor ( private readonly platform : QueryPlatform , options ?: { cacheTtlMs ?: number } ) {
@@ -49,6 +51,9 @@ export class KnowledgeQuerier {
4951 this . queryCache . set ( cacheKey , { response, cachedAt : new Date ( ) . toISOString ( ) , ttlMs : this . cacheTtlMs } ) ;
5052 this . pruneCache ( ) ;
5153
54+ // Track query pattern for analytics
55+ this . trackQueryPattern ( String ( request ?. query ?? '' ) . toLowerCase ( ) ) ;
56+
5257 // Augment response with domain-level telemetry
5358 return this . augmentQueryResponse ( response , latencyMs , request ) ;
5459 } catch ( error ) {
@@ -92,24 +97,60 @@ export class KnowledgeQuerier {
9297 }
9398
9499 getDiagnosticsSummary ( ) {
100+ const topQueries = [ ...this . queryPatternCounts . entries ( ) ]
101+ . sort ( ( a , b ) => b [ 1 ] - a [ 1 ] )
102+ . slice ( 0 , 10 )
103+ . map ( ( [ term , count ] ) => ( { term, count } ) ) ;
95104 return {
96105 queryCount : this . queryLatencyHistoryMs . length ,
97106 averageLatencyMs : this . averageQueryLatencyMs ( 20 ) ,
98107 latencyP95Ms : this . queryLatencyP95 ( 50 ) ,
108+ latencyP99Ms : this . queryLatencyP99 ( 100 ) ,
99109 fallbackCount : this . queryBackendFallbackCount ,
100110 lastError : this . queryBackendLastError ?? null ,
101111 lastQueryAt : this . lastQueryAt ,
102112 cacheSize : this . queryCache . size ,
103113 cacheHitRate : Number ( ( this . getCacheHitRate ( ) * 100 ) . toFixed ( 1 ) ) ,
104114 comparisonCount : this . comparisonCount ,
115+ slowQueryCount : this . slowQueryCount ,
116+ uniqueQueryTerms : this . queryPatternCounts . size ,
117+ topQueryTerms : topQueries ,
105118 } ;
106119 }
107120
121+ queryLatencyP99 ( n = 100 ) : number {
122+ const w = [ ...this . queryLatencyHistoryMs . slice ( - n ) ] . sort ( ( a , b ) => a - b ) ;
123+ if ( w . length === 0 ) return 0 ;
124+ return w [ Math . ceil ( w . length * 0.99 ) - 1 ] ;
125+ }
126+
108127 private recordLatency ( ms : number ) : void {
109128 this . queryLatencyHistoryMs . push ( ms ) ;
110129 if ( this . queryLatencyHistoryMs . length > 500 ) this . queryLatencyHistoryMs . shift ( ) ;
111130 }
112131
132+ /** Track query term frequency for pattern analysis. */
133+ private trackQueryPattern ( query : string ) : void {
134+ if ( ! query ) return ;
135+ const terms = query . split ( / \s + / ) . filter ( t => t . length > 2 ) ;
136+ for ( const term of terms ) {
137+ this . queryPatternCounts . set ( term , ( this . queryPatternCounts . get ( term ) || 0 ) + 1 ) ;
138+ }
139+ // Prune to top 200 terms
140+ if ( this . queryPatternCounts . size > 200 ) {
141+ const sorted = [ ...this . queryPatternCounts . entries ( ) ] . sort ( ( a , b ) => b [ 1 ] - a [ 1 ] ) ;
142+ this . queryPatternCounts = new Map ( sorted . slice ( 0 , 150 ) ) ;
143+ }
144+ }
145+
146+ /** Mark a query as slow (exceeds latency threshold). */
147+ private markSlowQuery ( latencyMs : number ) : void {
148+ const p95 = this . queryLatencyP95 ( 50 ) ;
149+ if ( p95 > 0 && latencyMs > p95 * 2 ) {
150+ this . slowQueryCount ++ ;
151+ }
152+ }
153+
113154 private buildCacheKey ( request : any ) : string {
114155 return [ request . query ?? '' , String ( request . topK ?? 10 ) , request . queryBackend ?? 'default' , request . asOf ?? '' ] . join ( '|' ) ;
115156 }
0 commit comments