feat: Enhance search ranking with name matching and field extraction improvements

Adds nameMatchBonus scoring to prioritize results where node names exactly or partially match query terms. Implements dedicated field extraction for Java/C# to properly categorize class fields vs variables. Optimizes BM25 search with column weights favoring name matches and increased result fetching before post-processing. Refines stop words list to preserve common programming terms like "get", "find", "list".
This commit is contained in:
Colby McHenry
2026-04-06 12:20:44 -05:00
parent b04ee9f9bb
commit e5663c5952
6 changed files with 128 additions and 11 deletions
+2 -1
View File
@@ -13,7 +13,8 @@ export const csharpExtractor: LanguageExtractor = {
typeAliasTypes: [],
importTypes: ['using_directive'],
callTypes: ['invocation_expression'],
variableTypes: ['local_declaration_statement', 'field_declaration'],
variableTypes: ['local_declaration_statement'],
fieldTypes: ['field_declaration'],
nameField: 'name',
bodyField: 'body',
paramsField: 'parameter_list',
+2 -1
View File
@@ -13,7 +13,8 @@ export const javaExtractor: LanguageExtractor = {
typeAliasTypes: [],
importTypes: ['import_declaration'],
callTypes: ['method_invocation'],
variableTypes: ['local_variable_declaration', 'field_declaration'],
variableTypes: ['local_variable_declaration'],
fieldTypes: ['field_declaration'],
nameField: 'name',
bodyField: 'body',
paramsField: 'parameters',
+2
View File
@@ -98,6 +98,8 @@ export interface LanguageExtractor {
callTypes: string[];
/** Node types that represent variable declarations (const, let, var, etc.) */
variableTypes: string[];
/** Node types that represent class fields (extracted as 'field' kind inside class bodies) */
fieldTypes?: string[];
// --- Field name mappings ---
+57
View File
@@ -276,6 +276,11 @@ export class TreeSitterExtractor {
else if (this.extractor.typeAliasTypes.includes(nodeType)) {
this.extractTypeAlias(node);
}
// Check for class fields (e.g. Java field_declaration, C# field_declaration)
else if (this.extractor.fieldTypes?.includes(nodeType) && this.isInsideClassLikeNode()) {
this.extractField(node);
skipChildren = true;
}
// Check for variable declarations (const, let, var, etc.)
// Only extract top-level variables (not inside functions/methods)
else if (this.extractor.variableTypes.includes(nodeType) && !this.isInsideClassLikeNode()) {
@@ -656,6 +661,58 @@ export class TreeSitterExtractor {
}
}
/**
* Extract a class field declaration (e.g. Java field_declaration, C# field_declaration).
* Extracts each declarator as a 'field' kind node inside the owning class.
*/
private extractField(node: SyntaxNode): void {
if (!this.extractor) return;
const docstring = getPrecedingDocstring(node, this.source);
const visibility = this.extractor.getVisibility?.(node);
const isStatic = this.extractor.isStatic?.(node) ?? false;
// Java field_declaration: "private final String name = value;"
// Children include modifiers, type, variable_declarator(s)
const declarators = node.namedChildren.filter(
c => c.type === 'variable_declarator'
);
if (declarators.length > 0) {
// Get field type from the type child
const typeNode = node.namedChildren.find(
c => c.type !== 'modifiers' && c.type !== 'variable_declarator'
&& c.type !== 'marker_annotation' && c.type !== 'annotation'
);
const typeText = typeNode ? getNodeText(typeNode, this.source) : undefined;
for (const decl of declarators) {
const nameNode = getChildByField(decl, 'name');
if (!nameNode) continue;
const name = getNodeText(nameNode, this.source);
const signature = typeText ? `${typeText} ${name}` : name;
this.createNode('field', name, decl, {
docstring,
signature,
visibility,
isStatic,
});
}
} else {
// Fallback: try to find an identifier child directly
const nameNode = getChildByField(node, 'name')
|| node.namedChildren.find(c => c.type === 'identifier');
if (nameNode) {
const name = getNodeText(nameNode, this.source);
this.createNode('field', name, node, {
docstring,
visibility,
isStatic,
});
}
}
}
/**
* Extract a variable declaration (const, let, var, etc.)
*