Compare commits
No commits in common. "142580cd963b2e21ad7c03cabb585059e46616c3" and "a291d33ffa9cd15e8eaee1a28120820ce7a1a118" have entirely different histories.
142580cd96
...
a291d33ffa
2 changed files with 10 additions and 57 deletions
35
doc/todo.md
35
doc/todo.md
|
|
@ -1,7 +1,5 @@
|
||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
## `search/main.py`
|
|
||||||
|
|
||||||
- [ ] P0: Переключить основной query на `question.search_text` с fallback на `question.text`
|
- [ ] P0: Переключить основной query на `question.search_text` с fallback на `question.text`
|
||||||
- [ ] P0: Подключить `question.variants` как дополнительные query-варианты
|
- [ ] P0: Подключить `question.variants` как дополнительные query-варианты
|
||||||
- [ ] P0: Подключить `question.hyde` как дополнительные dense-запросы
|
- [ ] P0: Подключить `question.hyde` как дополнительные dense-запросы
|
||||||
|
|
@ -10,16 +8,6 @@
|
||||||
- [ ] P0: Дедуплицировать `message_ids` перед ответом
|
- [ ] P0: Дедуплицировать `message_ids` перед ответом
|
||||||
- [ ] P0: Ограничить финальную выдачу до `top-50`
|
- [ ] P0: Ограничить финальную выдачу до `top-50`
|
||||||
- [ ] P0: Агрегировать score по `message_id`
|
- [ ] P0: Агрегировать score по `message_id`
|
||||||
- [ ] P2: Использовать `entities.people` и `entities.emails` для boost или фильтрации
|
|
||||||
- [ ] P2: Использовать `entities.documents`, `entities.names`, `entities.links` для lexical boost
|
|
||||||
- [ ] P2: Использовать `date_range` для фильтрации по `metadata.start` и `metadata.end`
|
|
||||||
- [ ] P2: Использовать `contains_quote` и `contains_forward` как сигналы ранжирования
|
|
||||||
- [ ] P2: Добавить multi-query fusion в `Qdrant`
|
|
||||||
- [ ] P2: Подобрать `prefetch`, `retrieve_k`, `rerank_limit`
|
|
||||||
- [ ] P3: Добавить retry и timeout политику для dense/rerank HTTP вызовов
|
|
||||||
|
|
||||||
## `index/main.py`
|
|
||||||
|
|
||||||
- [ ] P1: Перейти с символьного chunking на chunking по сообщениям
|
- [ ] P1: Перейти с символьного chunking на chunking по сообщениям
|
||||||
- [ ] P1: Учитывать time gap при сборке чанков
|
- [ ] P1: Учитывать time gap при сборке чанков
|
||||||
- [ ] P1: Маркировать в тексте `quote`, `forward`, автора сообщения и автора цитаты
|
- [ ] P1: Маркировать в тексте `quote`, `forward`, автора сообщения и автора цитаты
|
||||||
|
|
@ -27,23 +15,18 @@
|
||||||
- [ ] P1: Материализовать `sender_id` и `mentions` в индексируемый текст
|
- [ ] P1: Материализовать `sender_id` и `mentions` в индексируемый текст
|
||||||
- [ ] P1: Разбирать `file_snippets` и вытаскивать имя файла, mime и url
|
- [ ] P1: Разбирать `file_snippets` и вытаскивать имя файла, mime и url
|
||||||
- [ ] P1: Разбирать `member_event` и превращать его в индексируемый текст
|
- [ ] P1: Разбирать `member_event` и превращать его в индексируемый текст
|
||||||
|
- [ ] P2: Использовать `entities.people` и `entities.emails` для boost или фильтрации
|
||||||
## `docker-compose.yml`
|
- [ ] P2: Использовать `entities.documents`, `entities.names`, `entities.links` для lexical boost
|
||||||
|
- [ ] P2: Использовать `date_range` для фильтрации по `metadata.start` и `metadata.end`
|
||||||
|
- [ ] P2: Использовать `contains_quote` и `contains_forward` как сигналы ранжирования
|
||||||
|
- [ ] P2: Добавить multi-query fusion в `Qdrant`
|
||||||
|
- [ ] P2: Подобрать `prefetch`, `retrieve_k`, `rerank_limit`
|
||||||
- [ ] P3: Привести локальный `docker-compose.yml` к схеме с `API_KEY`
|
- [ ] P3: Привести локальный `docker-compose.yml` к схеме с `API_KEY`
|
||||||
- [ ] P3: Добавить `--platform linux/amd64` в сборку образов
|
- [ ] P3: Добавить `--platform linux/amd64` в сборку образов
|
||||||
|
- [ ] P3: Добавить retry и timeout политику для dense/rerank HTTP вызовов
|
||||||
## `doc/` (новый файл с регрессионными вопросами)
|
|
||||||
|
|
||||||
- [ ] P3: Зафиксировать набор локальных тестовых вопросов для проверки регрессий
|
- [ ] P3: Зафиксировать набор локальных тестовых вопросов для проверки регрессий
|
||||||
|
|
||||||
## `search/requirements.txt`
|
|
||||||
|
|
||||||
- [ ] P4: Добавить `python-dateutil` или `dateparser`
|
|
||||||
- [ ] P4: Добавить `tenacity`
|
|
||||||
|
|
||||||
## `index/requirements.txt` и/или `search/requirements.txt`
|
|
||||||
|
|
||||||
- [ ] P4: Добавить `razdel`
|
- [ ] P4: Добавить `razdel`
|
||||||
- [ ] P4: Добавить `pymorphy3`
|
- [ ] P4: Добавить `pymorphy3`
|
||||||
- [ ] P4: Добавить `rapidfuzz`
|
- [ ] P4: Добавить `rapidfuzz`
|
||||||
|
- [ ] P4: Добавить `python-dateutil` или `dateparser`
|
||||||
|
- [ ] P4: Добавить `tenacity`
|
||||||
|
|
|
||||||
|
|
@ -206,40 +206,12 @@ async def embed_sparse(text: str) -> SparseVector:
|
||||||
values=[float(value) for value in item.values.tolist()],
|
values=[float(value) for value in item.values.tolist()],
|
||||||
)
|
)
|
||||||
|
|
||||||
# ПЕРЕПИСАТЬ
|
|
||||||
|
|
||||||
async def qdrant_search(
|
async def qdrant_search(
|
||||||
client: AsyncQdrantClient,
|
client: AsyncQdrantClient,
|
||||||
dense_vector: list[float],
|
dense_vector: list[float],
|
||||||
sparse_vector: SparseVector,
|
sparse_vector: SparseVector,
|
||||||
question_data: Question
|
|
||||||
) -> Any | None:
|
) -> Any | None:
|
||||||
must_conditions: []
|
|
||||||
|
|
||||||
# Фильтр по диапазону дат (поле metadata.start в Qdrant) [cite: 147, 148, 175]
|
|
||||||
if question_data.date_range:
|
|
||||||
must_conditions.append(
|
|
||||||
models.FieldCondition(
|
|
||||||
key="metadata.start",
|
|
||||||
range=models.Range(
|
|
||||||
gte=question_data.date_range.from_,
|
|
||||||
lte=question_data.date_range.to_
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Фильтр по автору вопроса (поле metadata.participants) [cite: 161, 163]
|
|
||||||
if question_data.asker:
|
|
||||||
must_conditions.append(
|
|
||||||
models.FieldCondition(
|
|
||||||
key="metadata.participants",
|
|
||||||
match=models.MatchValue(value=question_data.asker)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Создаем итоговый объект фильтра, если есть условия
|
|
||||||
search_filter = models.Filter(must=must_conditions) if must_conditions else None
|
|
||||||
|
|
||||||
response = await client.query_points(
|
response = await client.query_points(
|
||||||
collection_name=QDRANT_COLLECTION_NAME,
|
collection_name=QDRANT_COLLECTION_NAME,
|
||||||
prefetch=[
|
prefetch=[
|
||||||
|
|
@ -247,7 +219,6 @@ async def qdrant_search(
|
||||||
query=dense_vector,
|
query=dense_vector,
|
||||||
using=QDRANT_DENSE_VECTOR_NAME,
|
using=QDRANT_DENSE_VECTOR_NAME,
|
||||||
limit=DENSE_PREFETCH_K,
|
limit=DENSE_PREFETCH_K,
|
||||||
filter=search_filter,
|
|
||||||
),
|
),
|
||||||
models.Prefetch(
|
models.Prefetch(
|
||||||
query=models.SparseVector(
|
query=models.SparseVector(
|
||||||
|
|
@ -256,7 +227,6 @@ async def qdrant_search(
|
||||||
),
|
),
|
||||||
using=QDRANT_SPARSE_VECTOR_NAME,
|
using=QDRANT_SPARSE_VECTOR_NAME,
|
||||||
limit=SPRASE_PREFETCH_K,
|
limit=SPRASE_PREFETCH_K,
|
||||||
filter=search_filter,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
query=models.FusionQuery(fusion=models.Fusion.RRF),
|
query=models.FusionQuery(fusion=models.Fusion.RRF),
|
||||||
|
|
@ -343,7 +313,7 @@ async def search(payload: SearchAPIRequest) -> SearchAPIResponse:
|
||||||
|
|
||||||
dense_vector = await embed_dense(client, query)
|
dense_vector = await embed_dense(client, query)
|
||||||
sparse_vector = await embed_sparse(query)
|
sparse_vector = await embed_sparse(query)
|
||||||
best_points = await qdrant_search(qdrant, dense_vector, sparse_vector, payload.question)
|
best_points = await qdrant_search(qdrant, dense_vector, sparse_vector)
|
||||||
|
|
||||||
if best_points is None:
|
if best_points is None:
|
||||||
return SearchAPIResponse(results=[])
|
return SearchAPIResponse(results=[])
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue