idea_world_labDEV JOURNAL
воскресенье, 28 июня 2026 г.

Альтернатива A: Сохранить текущий полнотекстовый поиск PostgreSQL

Поток работы

raw chunkText
  -> plainto_tsquery
  -> search_tsv @@ query
  -> ts_rank_cd
  -> top JSONL возврат

Преимущества

  • Уже реализовано.
  • Доступно только с PostgreSQL.
  • Инфраструктура проста.
  • search_tsv сразу подходит к таблице, которая уже его имеет.

Недостатки

  • Не BM25.
  • Слаб в длинных фрагментах кода.
  • Условие, созданное plainto_tsquery, может стать чрезмерно узким.
  • Слишком много шума от токенов кода.
  • Не выполняет семантический поиск.
  • При небольшом изменении разбиения фрагмента может не вернуть ни одного результата.

Ожидаемые проблемы в базовом фрагменте

В базовом фрагменте одновременно присутствуют следующие токены.

func
process
delta
velocity
vector2
zero
input
is_action_pressed
move_right
move_left
normalized
animatedsprite2d
play
stop
position
clamp
screen_size

Если все эти токены не находятся одновременно в одной строке JSONL, результаты поиска могут быть упущены.

Симуляция PoC

Предположим, что базовый чанк попадает в /api/retrieve без изменений.

(No content to translate)

chunkText = полный текст функции _process(delta)

Текущий метод преобразует этот ввод в plainto_tsquery('simple', chunkText).

Ожидаемый характер запроса:

func & process & delta & var & velocity & vector2 & zero
& input & is_action_pressed & move_right & move_left
& length & normalized & speed & animatedsprite2d
& play & stop & position & clamp & screen_size

В этом случае, если фактический связанный документ разделён на два куска, как показано ниже, возникает проблема.

docs chunk A:
  Input.is_action_pressed("move_right")
  Input.is_action_pressed("move_left")
  velocity.normalized() * speed
  $AnimatedSprite2D.play()
  $AnimatedSprite2D.stop()

docs chunk B:
  position += velocity * delta
  position = position.clamp(Vector2.ZERO, screen_size)

Если человек смотрит, A и B оба связаны.

Однако если full-text query требует одновременно слишком много токенов, это может привести к следующему.

docs chunk A:
  animatedsprite2d = есть
  is_action_pressed = есть
  move_left/move_right = есть
  clamp = нет
  screen_size = нет
  position.clamp = нет
  => запрос не полностью удовлетворён

docs chunk B:
  clamp = есть
  screen_size = есть
  position = есть
  animatedsprite2d = отсутствует или слабый
  move_left/move_right = нет
  is_action_pressed = нет
  => запрос не полностью удовлетворён

Видимые формы неудач:

Результатов поиска 0  
или возвращает только очень узкий chunk

В этом подходе трудно различить, является ли ошибка поиска «неудачей из‑за отсутствия доказательств в документе» или «неудачей из‑за слишком строгих условий запроса».

Логи, проверяемые в PoC

При тестировании этой альтернативы нельзя смотреть только на результат.

Необходимо также показывать следующие значения.

1. необработанный chunkText  
2. запрос, созданный с помощью plainto_tsquery  
3. список токенов, входящих в запрос  
4. количество возвращаемых строк  
5. если 0 записей, какой токен сделал запрос слишком узким

Ожидаемое наблюдение:

Чем длиннее raw chunk, тем длиннее запрос, а если связанные документы разбиты на несколько chunk, результат будет неполным.

Оценка

Можно использовать в качестве базовой линии PoC.
В качестве окончательной стратегии поиска — кандидат на удаление

Оценка оригинальной заметки ближе к «нужно всё переделать».