feat(search): PDF-контент в поиске — свой индекс oo_docs_text (#42) #44

Merged
eSlider merged 3 commits from feat/pdf-content#42 into main 2026-09-16 18:34:54 +01:00
Owner

Epic: #34 · Issue: #42 (F6). Обновлено: ребейз на main (F2 #45, F4 #43) + встроенные вложения PDF.

Что

PDF-контент стал искомым, включая текст встроенных вложений.
oo search --content "S1021" --backend own находит PDF-счёт; индекс OnlyOffice
(files_file) не трогаем.

Research: почему PDF исключён

В ONLYOFFICE/CommunityServer:

  • web/core/ASC.Web.Core/Files/FileUtility.cs — CanIndex читает серверную
    настройку files.index.formats (default ".pptx|.xlsx|.docx").
  • Products/Files/Core/Search/FilesWrapper.cs — GetDocumentStream* → null
    при !CanIndex/encrypted/большой файл.
  • ASC.ElasticSearch/Core/WrapperWithDoc.cs + маппинг — формат-агностичны.

Вывод: PDF исключён настройкой. Решение — вариант c: свой индекс
oo_docs_text, наполняемый internal/docpipe; сервер OO не трогаем.
Зафиксировано в docs/elasticsearch.md.

Встроенные вложения

Оцифрованные PDF несут вложения (<doc>.md — текст скана, .yaml/.json —
метаданные, .xml — EN 16931/ZUGFeRD; см.
office-assistant/docs/reference/document-metadata.md).
TextIndexer вызывает docpipe.ToMarkdownWithAttachments: тело + по секции на
вложение с маркером [attachment: <имя>].

  • internal/docpipe/pdfattach.go — ListAttachments (pdfdetach -list),
    SaveAttachment (-save), JoinWithAttachments, xmlToText (снятие тегов
    для XML/HTML-вложений), безопасные имена.
  • .md/.txt/PDF/картинки — штатный docpipe (OCR для сканов); .json/.csv
    — как текст; нечитаемое — пропускается; pdfdetach отсутствует — только тело.
  • Индекс — тот же file_id, upsert идемпотентен.

Реализация

  • file_es_text.go — ESTextIndex: Ensure/Put/Delete/Search
    (multi_match title^2+content, фильтры folder/ext, highlight).
  • file_text_index.go — TextIndexer (FileStore.List/Stat/Download →
    docpipe → TextIndex; пул воркеров; PlanFolder/PlanFiles).
  • CLI: oo index folder|files (--recursive --exts --limit --workers --dry-run),
    oo search --backend oo|own.
  • Docs/README/.env.example (ONLYOFFICE_ES_TEXT_INDEX, default oo_docs_text).
  • Ребейз: file_facade.go — убран дубликат ProviderPG (main не собирался
    после мержа F4+F2); тестовый fakeStore переименован (textFakeStore) —
    конфликт с фасадом.

Тесты

Unit (без сети):

  • root: TestESTextSearchRequestShape, TestESTextBulkBody,
    TestParseESTextResponse, TestNewESTextIndexDefaults,
    TestESTextConfigFromEnvIndexDefault, TestTextIndexerIndexEntries,
    TestTextIndexerRecordsExtractionFailure, TestTextIndexerPlanFolder.
  • docpipe: TestParseAttachmentList, TestParseAttachmentListEmptyAndMalformed,
    TestSafeAttachmentName, TestJoinWithAttachments,
    TestJoinWithAttachmentsNoAttachments, TestListAttachmentsWithoutTool,
    TestXMLToText, TestAttachmentMarkdownFallback,
    TestToMarkdownWithAttachmentsFixture (реальный pdfdetach+pdftotext),
    TestToMarkdownWithAttachmentsPlainPDF.
  • cmd/oo: TestIndexCommandRegistered, TestIndexSearchBackendFlag,
    TestSplitList. Все PASS.

Integration (-tags=integration, skip без ONLYOFFICE_ES_URL):

  • TestIntegrationESTextIndex, TestIntegrationESTextIndexPDFAttachment
    (fixture → реальный конвейер → поиск токена только из вложения),
    регрессия TestIntegrationESSearch — PASS live.

go build ./..., go vet ./..., go test -race ./... — зелёные.
gitleaks — no leaks; po scan — clean.

Live-проверка (индекс oo_docs_text)

Встроенные вложения (реальный OO-файл 21749, factur-x.xml):

  • oo index files 21749 → маркер [attachment: factur-x.xml] в индексе;
  • IBAN DE26330403100827038100 из XML → найден --backend own, --backend oo
    — пусто; тот же OO-файл без вложений — не находился.

Шесть номеров (папки 634/639, 22 PDF; вложений в этих PDF нет):

  • S1019 → 3576 · S1020 → 3577 · S1021 → 3578 · S1030 → 3581 ·
    S1055 → 3591 и 3584 — все найдены по телу (не по вложению);
  • S1063 → пусто (документа нет ни в OO, ни в локальном корпусе, в т.ч. во
    вложениях).

Не мержу и не закрываю.

Epic: #34 · Issue: #42 (F6). Обновлено: ребейз на `main` (F2 #45, F4 #43) + встроенные вложения PDF. ## Что PDF-контент стал искомым, включая текст **встроенных вложений**. `oo search --content "S1021" --backend own` находит PDF-счёт; индекс OnlyOffice (`files_file`) не трогаем. ## Research: почему PDF исключён В `ONLYOFFICE/CommunityServer`: - `web/core/ASC.Web.Core/Files/FileUtility.cs` — `CanIndex` читает серверную настройку `files.index.formats` (default `".pptx|.xlsx|.docx"`). - `Products/Files/Core/Search/FilesWrapper.cs` — `GetDocumentStream*` → `null` при `!CanIndex`/encrypted/большой файл. - `ASC.ElasticSearch/Core/WrapperWithDoc.cs` + маппинг — формат-агностичны. Вывод: PDF исключён **настройкой**. Решение — вариант **c**: свой индекс `oo_docs_text`, наполняемый `internal/docpipe`; сервер OO не трогаем. Зафиксировано в `docs/elasticsearch.md`. ## Встроенные вложения Оцифрованные PDF несут вложения (`<doc>.md` — текст скана, `.yaml`/`.json` — метаданные, `.xml` — EN 16931/ZUGFeRD; см. `office-assistant/docs/reference/document-metadata.md`). `TextIndexer` вызывает `docpipe.ToMarkdownWithAttachments`: тело + по секции на вложение с маркером `[attachment: <имя>]`. - `internal/docpipe/pdfattach.go` — `ListAttachments` (`pdfdetach -list`), `SaveAttachment` (`-save`), `JoinWithAttachments`, `xmlToText` (снятие тегов для XML/HTML-вложений), безопасные имена. - `.md`/`.txt`/PDF/картинки — штатный docpipe (OCR для сканов); `.json`/`.csv` — как текст; нечитаемое — пропускается; `pdfdetach` отсутствует — только тело. - Индекс — тот же `file_id`, upsert идемпотентен. ## Реализация - `file_es_text.go` — `ESTextIndex`: `Ensure`/`Put`/`Delete`/`Search` (`multi_match` title^2+content, фильтры folder/ext, highlight). - `file_text_index.go` — `TextIndexer` (`FileStore.List/Stat/Download` → docpipe → `TextIndex`; пул воркеров; `PlanFolder/PlanFiles`). - CLI: `oo index folder|files` (`--recursive --exts --limit --workers --dry-run`), `oo search --backend oo|own`. - Docs/README/.env.example (`ONLYOFFICE_ES_TEXT_INDEX`, default `oo_docs_text`). - Ребейз: `file_facade.go` — убран дубликат `ProviderPG` (main не собирался после мержа F4+F2); тестовый `fakeStore` переименован (`textFakeStore`) — конфликт с фасадом. ## Тесты Unit (без сети): - root: `TestESTextSearchRequestShape`, `TestESTextBulkBody`, `TestParseESTextResponse`, `TestNewESTextIndexDefaults`, `TestESTextConfigFromEnvIndexDefault`, `TestTextIndexerIndexEntries`, `TestTextIndexerRecordsExtractionFailure`, `TestTextIndexerPlanFolder`. - docpipe: `TestParseAttachmentList`, `TestParseAttachmentListEmptyAndMalformed`, `TestSafeAttachmentName`, `TestJoinWithAttachments`, `TestJoinWithAttachmentsNoAttachments`, `TestListAttachmentsWithoutTool`, `TestXMLToText`, `TestAttachmentMarkdownFallback`, `TestToMarkdownWithAttachmentsFixture` (реальный pdfdetach+pdftotext), `TestToMarkdownWithAttachmentsPlainPDF`. - cmd/oo: `TestIndexCommandRegistered`, `TestIndexSearchBackendFlag`, `TestSplitList`. Все PASS. Integration (`-tags=integration`, skip без `ONLYOFFICE_ES_URL`): - `TestIntegrationESTextIndex`, `TestIntegrationESTextIndexPDFAttachment` (fixture → реальный конвейер → поиск токена только из вложения), регрессия `TestIntegrationESSearch` — PASS live. `go build ./...`, `go vet ./...`, `go test -race ./...` — зелёные. gitleaks — no leaks; `po scan` — clean. ## Live-проверка (индекс `oo_docs_text`) Встроенные вложения (реальный OO-файл 21749, `factur-x.xml`): - `oo index files 21749` → маркер `[attachment: factur-x.xml]` в индексе; - IBAN `DE26330403100827038100` из XML → найден `--backend own`, `--backend oo` — пусто; тот же OO-файл без вложений — не находился. Шесть номеров (папки 634/639, 22 PDF; вложений в этих PDF нет): - S1019 → 3576 · S1020 → 3577 · S1021 → 3578 · S1030 → 3581 · S1055 → 3591 и 3584 — все найдены **по телу** (не по вложению); - S1063 → пусто (документа нет ни в OO, ни в локальном корпусе, в т.ч. во вложениях). Не мержу и не закрываю.
Yftyr added 3 commits 2026-09-16 18:34:13 +01:00
feat(search): index embedded PDF attachment text (#42)
Release Please / Release Please (push) Skipped
Release / GoReleaser (push) Skipped
Tests / Secret scan (gitleaks) (push) Skipped
Tests / Test (Go 1.25) (push) Skipped
Tests / Test (Go stable) (push) Skipped
Tests / Secret scan (gitleaks) (pull_request) Successful in 4s
Tests / Test (Go stable) (pull_request) Successful in 25s
Tests / Test (Go 1.25) (pull_request) Successful in 28s
3cc288d281
Yftyr force-pushed feat/pdf-content#42 from 7c3a0b8b6e to 3cc288d281 2026-09-16 18:34:13 +01:00 Compare
eSlider merged commit c76ab7267d into main 2026-09-16 18:34:54 +01:00
eSlider deleted branch feat/pdf-content#42 2026-09-16 18:34:54 +01:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: eSlider/go-onlyoffice#44