* Perform a full-text search with relevance scoring. * Returns results sorted by score descending. * * @param query The search query. * @param limit Maximum number of results (0 = unlimited). * @param minScore Minimum score threshold (0-1). * @returns Array of results with scores,
(query: string, limit: number = 0, minScore: number = 0)
| 110 | * @returns Array of results with scores, sorted by relevance. |
| 111 | */ |
| 112 | public search(query: string, limit: number = 0, minScore: number = 0): FullTextSearchResult[] { |
| 113 | if (!query || query.trim().length === 0) { |
| 114 | return []; |
| 115 | } |
| 116 | |
| 117 | // Extract query terms to find candidate documents |
| 118 | const queryTerms = extractTerms(query, this.#options); |
| 119 | |
| 120 | if (queryTerms.length === 0) { |
| 121 | return []; |
| 122 | } |
| 123 | |
| 124 | // Find candidate documents (any that contain at least one query term) |
| 125 | const candidates = new Set<ElementId>(); |
| 126 | for (const term of queryTerms) { |
| 127 | const ids = this.#invertedIndex.get(term); |
| 128 | if (ids) { |
| 129 | for (const id of ids) { |
| 130 | candidates.add(id); |
| 131 | } |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | if (candidates.size === 0) { |
| 136 | return []; |
| 137 | } |
| 138 | |
| 139 | // Create matcher for scoring |
| 140 | const matcher = createMatcher(query, this.#options); |
| 141 | |
| 142 | // Score all candidates |
| 143 | const results: FullTextSearchResult[] = []; |
| 144 | |
| 145 | for (const elementId of candidates) { |
| 146 | const text = this.#documents.get(elementId); |
| 147 | if (!text) continue; |
| 148 | |
| 149 | const score = matcher(text); |
| 150 | |
| 151 | if (score >= minScore) { |
| 152 | results.push({ elementId, score }); |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | // Sort by score descending |
| 157 | results.sort((a, b) => b.score - a.score); |
| 158 | |
| 159 | // Apply limit |
| 160 | if (limit > 0 && results.length > limit) { |
| 161 | return results.slice(0, limit); |
| 162 | } |
| 163 | |
| 164 | return results; |
| 165 | } |
| 166 | |
| 167 | /** |
| 168 | * Find documents where the text contains the given substring. |
no test coverage detected