fix(api): part-number ILIKE search + verified-first catalog ordering + FTS-primary product search
This commit is contained in:
parent
9979b79434
commit
d6da7aa94c
@ -28,7 +28,7 @@ export async function searchTransceivers(params: SearchParams) {
|
||||
let idx = 1;
|
||||
|
||||
if (params.q) {
|
||||
conditions.push(`search_vector @@ plainto_tsquery('english', $${idx})`);
|
||||
conditions.push(`(search_vector @@ plainto_tsquery('english', $${idx}) OR t.part_number ILIKE '%' || $${idx} || '%' OR t.standard_name ILIKE '%' || $${idx} || '%')`);
|
||||
values.push(params.q);
|
||||
idx++;
|
||||
}
|
||||
@ -98,8 +98,8 @@ export async function searchTransceivers(params: SearchParams) {
|
||||
|
||||
// Add relevance ranking when full-text search is used
|
||||
const orderBy = params.q
|
||||
? `ORDER BY ts_rank(search_vector, plainto_tsquery('english', $1)) DESC`
|
||||
: `ORDER BY speed_gbps DESC, reach_meters ASC`;
|
||||
? `ORDER BY (t.part_number ILIKE $1) DESC, ts_rank(search_vector, plainto_tsquery('english', $1)) DESC, fully_verified DESC NULLS LAST, has_image DESC NULLS LAST`
|
||||
: `ORDER BY fully_verified DESC NULLS LAST, has_image DESC NULLS LAST, speed_gbps DESC NULLS LAST, reach_meters ASC NULLS LAST`;
|
||||
|
||||
const query = `
|
||||
SELECT t.*, v.name as vendor_name
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
*/
|
||||
import { Router, Request, Response } from "express";
|
||||
import { semanticSearch, getCollectionInfo, CollectionName } from "../embeddings/client";
|
||||
import { searchTransceivers } from "../db/queries";
|
||||
|
||||
export const searchRouter = Router();
|
||||
|
||||
@ -43,11 +44,20 @@ searchRouter.get("/", async (req: Request, res: Response) => {
|
||||
}
|
||||
|
||||
try {
|
||||
const results = await semanticSearch(collection, query, limit);
|
||||
let results: any[];
|
||||
let usedFallback = false;
|
||||
if (collection === "product_embeddings") {
|
||||
const fts = await searchTransceivers({ q: query, limit });
|
||||
results = (((fts as any).data) || []).map((t: any) => ({ id: t.id, score: 0.5, payload: t }));
|
||||
usedFallback = true;
|
||||
} else {
|
||||
results = await semanticSearch(collection, query, limit);
|
||||
}
|
||||
res.json({
|
||||
success: true,
|
||||
query,
|
||||
collection,
|
||||
fallback: usedFallback ? "fts" : undefined,
|
||||
results: results.map((r) => ({
|
||||
id: r.id,
|
||||
score: Math.round(r.score * 1000) / 1000,
|
||||
@ -56,6 +66,14 @@ searchRouter.get("/", async (req: Request, res: Response) => {
|
||||
count: results.length,
|
||||
});
|
||||
} catch (err) {
|
||||
if (collection === "product_embeddings") {
|
||||
try {
|
||||
const fts = await searchTransceivers({ q: query, limit });
|
||||
const results = (((fts as any).data) || []).map((t: any) => ({ id: t.id, score: 0.5, ...t }));
|
||||
res.json({ success: true, query, collection, fallback: "fts", results, count: results.length });
|
||||
return;
|
||||
} catch (e2) { /* fall through */ }
|
||||
}
|
||||
res.status(503).json({
|
||||
success: false,
|
||||
error: "Vector search unavailable",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user