|
17 | 17 | /** In-memory, metadata-only lexical ranking for the active schema. */ |
18 | 18 | final class SchemaSearchRanker { |
19 | 19 | private static final int MAX_QUERY_TERMS = 32; |
20 | | - private static final int MAX_MATCH_REASONS = 6; |
21 | 20 | private static final int CONTEXT_TABLE_BOOST = 5; |
22 | 21 | private static final int COVERAGE_BONUS = 6; |
| 22 | + private static final List<String> MATCH_SOURCES = List.of( |
| 23 | + "table_name", "table_comment", "column_name", "column_comment" |
| 24 | + ); |
23 | 25 |
|
24 | 26 | private SchemaSearchRanker() { |
25 | 27 | } |
@@ -73,12 +75,11 @@ static RankedResults rank( |
73 | 75 | for (String term : terms) { |
74 | 76 | int nameScore = fieldScore(term, column.name(), 9, 7, 5); |
75 | 77 | if (nameScore > 0) { |
76 | | - candidate.match(term, nameScore, "column: " + preview(column.name(), 96)); |
| 78 | + candidate.match(term, nameScore, "column_name"); |
77 | 79 | } |
78 | 80 | int commentScore = fieldScore(term, column.comment(), 7, 6, 4); |
79 | 81 | if (commentScore > 0) { |
80 | | - candidate.match(term, commentScore, "column: " + preview(column.name(), 96) |
81 | | - + " / " + preview(column.comment(), 128)); |
| 82 | + candidate.match(term, commentScore, "column_comment"); |
82 | 83 | } |
83 | 84 | } |
84 | 85 | } |
@@ -112,18 +113,18 @@ private static void addRelationMatches(Candidate candidate, List<String> terms, |
112 | 113 | String table = candidate.relation.ref().name(); |
113 | 114 | String comment = candidate.relation.comment(); |
114 | 115 | if (normalize(table).equals(exactQuery)) { |
115 | | - candidate.exactMatch(12, "table_name: exact " + preview(table, 128)); |
| 116 | + candidate.exactMatch(12, "table_name"); |
116 | 117 | } else if (comment != null && normalize(comment).equals(exactQuery)) { |
117 | | - candidate.exactMatch(6, "table_comment: exact " + preview(comment, 160)); |
| 118 | + candidate.exactMatch(6, "table_comment"); |
118 | 119 | } |
119 | 120 | for (String term : terms) { |
120 | 121 | int nameScore = fieldScore(term, table, 18, 12, 8); |
121 | 122 | if (nameScore > 0) { |
122 | | - candidate.match(term, nameScore, "table_name: " + preview(table, 128)); |
| 123 | + candidate.match(term, nameScore, "table_name"); |
123 | 124 | } |
124 | 125 | int commentScore = fieldScore(term, comment, 12, 10, 7); |
125 | 126 | if (commentScore > 0) { |
126 | | - candidate.match(term, commentScore, "table_comment: " + preview(comment, 160)); |
| 127 | + candidate.match(term, commentScore, "table_comment"); |
127 | 128 | } |
128 | 129 | } |
129 | 130 | } |
@@ -212,74 +213,48 @@ private static boolean isCurrentTable(RelationMetadata relation, String currentT |
212 | 213 | return currentTable != null && currentTable.equals(relation.ref().name()); |
213 | 214 | } |
214 | 215 |
|
215 | | - private static String preview(String value, int maximum) { |
216 | | - if (value == null) { |
217 | | - return ""; |
218 | | - } |
219 | | - return value.length() <= maximum ? value : value.substring(0, maximum) + "…"; |
220 | | - } |
221 | | - |
222 | 216 | record RankedResults(List<Map<String, Object>> candidates, boolean truncated) { |
223 | 217 | } |
224 | 218 |
|
225 | 219 | private record ScoredRelation(RelationMetadata relation, int score) { |
226 | 220 | } |
227 | 221 |
|
228 | | - private record Match(int weight, String reason) { |
229 | | - } |
230 | | - |
231 | 222 | private static final class Candidate { |
232 | 223 | private final RelationMetadata relation; |
233 | 224 | private final boolean currentTable; |
234 | | - private final Map<String, Match> matches = new LinkedHashMap<>(); |
| 225 | + private final Map<String, Integer> matches = new LinkedHashMap<>(); |
| 226 | + private final Set<String> matchedSources = new LinkedHashSet<>(); |
235 | 227 | private int exactQueryBonus; |
236 | | - private String exactQueryReason; |
237 | 228 |
|
238 | 229 | private Candidate(RelationMetadata relation, boolean currentTable) { |
239 | 230 | this.relation = relation; |
240 | 231 | this.currentTable = currentTable; |
241 | 232 | } |
242 | 233 |
|
243 | | - private void match(String term, int weight, String reason) { |
244 | | - Match previous = matches.get(term); |
245 | | - if (previous == null || weight > previous.weight()) { |
246 | | - matches.put(term, new Match(weight, reason)); |
247 | | - } |
| 234 | + private void match(String term, int weight, String source) { |
| 235 | + matchedSources.add(source); |
| 236 | + matches.merge(term, weight, Math::max); |
248 | 237 | } |
249 | 238 |
|
250 | | - private void exactMatch(int weight, String reason) { |
| 239 | + private void exactMatch(int weight, String source) { |
251 | 240 | exactQueryBonus = weight; |
252 | | - exactQueryReason = reason; |
| 241 | + matchedSources.add(source); |
253 | 242 | } |
254 | 243 |
|
255 | 244 | private int score() { |
256 | | - return matches.values().stream().mapToInt(Match::weight).sum() |
| 245 | + return matches.values().stream().mapToInt(Integer::intValue).sum() |
257 | 246 | + Math.max(0, matches.size() - 1) * COVERAGE_BONUS |
258 | 247 | + exactQueryBonus |
259 | 248 | + (currentTable ? CONTEXT_TABLE_BOOST : 0); |
260 | 249 | } |
261 | 250 |
|
262 | 251 | private Map<String, Object> serialize() { |
263 | | - Set<String> reasons = new LinkedHashSet<>(); |
264 | | - if (currentTable) { |
265 | | - reasons.add("context_table: current table"); |
266 | | - } |
267 | | - if (exactQueryReason != null) { |
268 | | - reasons.add(exactQueryReason); |
269 | | - } |
270 | | - for (Match match : matches.values()) { |
271 | | - reasons.add(match.reason()); |
272 | | - if (reasons.size() >= MAX_MATCH_REASONS) { |
273 | | - break; |
274 | | - } |
275 | | - } |
276 | 252 | Map<String, Object> result = new LinkedHashMap<>(); |
277 | 253 | result.put("table", relation.ref().name()); |
278 | | - result.put("comment", preview(relation.comment(), 256)); |
279 | 254 | result.put("score", score()); |
280 | 255 | result.put("matchedKeywords", matches.size()); |
281 | 256 | result.put("currentTable", currentTable); |
282 | | - result.put("matches", List.copyOf(reasons)); |
| 257 | + result.put("matchedOn", MATCH_SOURCES.stream().filter(matchedSources::contains).toList()); |
283 | 258 | return result; |
284 | 259 | } |
285 | 260 | } |
|
0 commit comments