F3 — Elasticsearch-клиент поиска (имя + контент) + oo search #37

Closed
opened 2026-09-16 17:21:06 +01:00 by eSlider · 1 comment
Owner

Epic: #34

F3 — Elasticsearch-клиент поиска (имя + содержимое) + oo search

Что выяснено (research в исходниках CommunityServer)

  • Полнотекстовый поиск OnlyOffice — Elasticsearch; клиент NEST.
  • Индекс = имя таблицы: для файлов files_file (Wrapper.IndexName => Table),
    есть tenant_id; контент документа — document.attachment.content
    (WrapperWithDoc, ingest-attachment).
  • REST GET /api/2.0/files/@search/{query} — это только БД по имени
    (fileDao.Search, SearchHandler.SearchFiles), ES не задействует.
    Значит для контент-поиска нужен прямой ES.
  • Конфиг ES у сервера: ElasticSection host/port/scheme (дефолт
    localhost:9200). Снаружи :9200 не открыт (проверено); SSH в VM открыт
    (127.0.0.1:32) → нужен туннель; либо expose. — инфра-шаг.

Реализация

  • file_es.go: esStore/esSearcher — прямой ES REST (stdlib net/http или
    канонический github.com/elastic/go-elasticsearch/v8, выбрать по версии ES).
    • Search(SearchQuery) → запрос по title и document.attachment.content
      (multi_match), фильтр tenant_id, _source id/title/folder_id,
      highlight для фрагмента. Возвращает []SearchHit с Entry (маппинг
      id → files_file).
    • Name() = "elasticsearch".
  • Конфиг: ONLYOFFICE_ES_URL (scheme+host+port), ONLYOFFICE_ES_INDEX
    (default files_file), ONLYOFFICE_TENANT.
  • CLI: oo search <query> [--content] [--folder id] [--json] — тонкая обёртка.
  • Инфра: туннель к ES VM (SSH 127.0.0.1:32) или expose :9200; задокументировать.

Тесты/критерии

  • Unit: построение ES-запроса и парсинг ответа/highlight (чистые функции).
  • Integration (//go:build integration, skip без ONLYOFFICE_ES_URL):
    поиск по имени и по содержимому находит заранее залитый тестовый файл.
  • CLI oo search работает и уважает --output json.
  • go build/vet/test зелёные; секретов нет.
Epic: #34 ## F3 — Elasticsearch-клиент поиска (имя + содержимое) + `oo search` ### Что выяснено (research в исходниках CommunityServer) - Полнотекстовый поиск OnlyOffice — **Elasticsearch**; клиент `NEST`. - Индекс = имя таблицы: для файлов **`files_file`** (`Wrapper.IndexName => Table`), есть `tenant_id`; контент документа — `document.attachment.content` (`WrapperWithDoc`, ingest-attachment). - REST `GET /api/2.0/files/@search/{query}` — это **только БД по имени** (`fileDao.Search`, `SearchHandler.SearchFiles`), **ES не задействует**. Значит для контент-поиска нужен **прямой ES**. - Конфиг ES у сервера: `ElasticSection` host/port/scheme (дефолт `localhost:9200`). **Снаружи `:9200` не открыт** (проверено); SSH в VM открыт (`127.0.0.1:32`) → нужен туннель; либо expose. — инфра-шаг. ### Реализация - `file_es.go`: `esStore`/`esSearcher` — прямой ES REST (stdlib `net/http` или канонический `github.com/elastic/go-elasticsearch/v8`, выбрать по версии ES). - `Search(SearchQuery)` → запрос по `title` и `document.attachment.content` (`multi_match`), фильтр `tenant_id`, `_source` id/title/folder_id, `highlight` для фрагмента. Возвращает `[]SearchHit` с `Entry` (маппинг id → `files_file`). - `Name() = "elasticsearch"`. - Конфиг: `ONLYOFFICE_ES_URL` (scheme+host+port), `ONLYOFFICE_ES_INDEX` (default `files_file`), `ONLYOFFICE_TENANT`. - CLI: `oo search <query> [--content] [--folder id] [--json]` — тонкая обёртка. - Инфра: туннель к ES VM (SSH `127.0.0.1:32`) или expose `:9200`; задокументировать. ### Тесты/критерии - [ ] Unit: построение ES-запроса и парсинг ответа/highlight (чистые функции). - [ ] Integration (`//go:build integration`, skip без `ONLYOFFICE_ES_URL`): поиск по имени и **по содержимому** находит заранее залитый тестовый файл. - [ ] CLI `oo search` работает и уважает `--output json`. - [ ] `go build/vet/test` зелёные; секретов нет.
eSlider added the feature label 2026-09-16 17:21:13 +01:00
Author
Owner

F3 — отчёт: Elasticsearch-клиент поиска (имя + контент) + oo search

PR: #41
Ветка feat/es-search#37 · коммит 33b5c1e (base main).
Не мержу и не закрываю.

Доступ к ES (research, live) — блокера нет

  • ES живёт внутри VM OnlyOffice (onlyoffice-v2), слушает
    127.0.0.1:9200; версия 7.16.3, cluster elasticsearch. Снаружи
    :9200 закрыт, SSH в VM открыт как 127.0.0.1:32.
  • Креды SSH VM уже на хосте (~/.ssh/id_ed25519, root@127.0.0.1:32).
  • Туннель проверен live:
    ssh -f -N -o ControlMaster=no -o ControlPath=none \
        -p 32 -i ~/.ssh/id_ed25519 \
        -L 9200:127.0.0.1:9200 root@127.0.0.1
    curl -s http://127.0.0.1:9200/          # 7.16.3
    curl -s 'http://127.0.0.1:9200/_cat/indices?h=index,docs.count'
    
    ControlMaster=no / ControlPath=none обязательны — иначе forward уходит в
    persistent master из ~/.ssh/config.
  • Индекс files_file (~39.8k док-в), _count ОК.
  • Факты live поправили формулировку issue: поля не tenant_id/folder_id,
    а tenantId (integer) и folders[].folderId (строка). Контент —
    document.attachment.content; заполняется только для Office-форматов
    (docx/xlsx/pptx), у PDF/txt, залитых через API, контента нет.
  • title analyzer whitespacecustom — режет по пробелам/lower-case, полное
    имя файла = один токен. REST @search по-прежнему только по имени в БД.

Реализация

  • file_es.go: ESSearcher — прямой ES REST на stdlib net/http (без новых
    зависимостей). Search(SearchQuery):
    • multi_match по title^2; при InContent + document.attachment.content;
    • фильтр tenantId (env ONLYOFFICE_TENANT) и folders.folderId;
    • _source id/title/folders, highlight (теги <em> срезаются);
    • возвращает []SearchHit; Name() = "elasticsearch".
  • Модель Entry/Kind/SearchHit/SearchQuery/Searcher — из F1 #35;
    пока объявлена в file_es.go (F1 ещё не влит), при мерже переезжает в
    file_core.go — согласуем.
  • Конфиг: ONLYOFFICE_ES_URL, ONLYOFFICE_ES_INDEX (default files_file),
    ONLYOFFICE_TENANT. .env.example — только имена.
  • CLI oo search <query> [--content] [--folder id] [--limit N] [--json] —
    тонкая обёртка через printTable/printJSON.
  • docs/elasticsearch.md: устройство поиска, схема полей, туннель, env,
    грабли (анализ title, контент только Office, async-индексация).

Тесты (имена + PASS)

  • Unit file_es_test.go: TestESSearchRequestNameOnly,
    TestESSearchRequestContentFields, TestESSearchRequestFiltersAndLimit,
    TestNewESSearcherRequiresURL, TestNormalizeExtensions,
    TestParseESSearchResponse, TestESSearchRequestJSONShape — PASS.
  • CLI cmd/oo/search_test.go:
    TestSearchCommandRegisteredWithFlags,
    TestSearchWithoutESURLIsClearError — PASS.
  • Integration file_es_integration_test.go (//go:build integration, skip без
    ONLYOFFICE_ES_URL): TestIntegrationESSearch — заливает временный xlsx
    (уникальные токены в имени и в ячейке), ждёт асинхронной индексации, находит
    по имени и по контенту, проверяет highlight и что name-only поиск не
    находит content-токен, затем удаляет проект. PASS live (туннель).
  • go build ./... && go vet ./... && go test -race ./... — зелёные.
    gitleaks — no leaks found. Секретов в коде нет.

Примечание: go vet -tags=integration ./... падает на чужом файле
cmd/office/fetch/task_integration_test.go:60 (loader.TaskFields undefined) —
существует на main, к PR не относится.

Блокеры

Нет. ES доступен через SSH-туннель; на постоянку его можно завернуть в
systemd-юнит (как vado-vision-tunnel) — отдельная инфра-задача.

## F3 — отчёт: Elasticsearch-клиент поиска (имя + контент) + `oo search` PR: https://git.produktor.io/eSlider/go-onlyoffice/pulls/41 Ветка `feat/es-search#37` · коммит `33b5c1e` (base `main`). Не мержу и не закрываю. ### Доступ к ES (research, live) — блокера нет - ES живёт **внутри VM** OnlyOffice (`onlyoffice-v2`), слушает `127.0.0.1:9200`; **версия 7.16.3**, cluster `elasticsearch`. Снаружи `:9200` закрыт, SSH в VM открыт как `127.0.0.1:32`. - Креды SSH VM уже на хосте (`~/.ssh/id_ed25519`, root@127.0.0.1:32). - Туннель проверен live: ```bash ssh -f -N -o ControlMaster=no -o ControlPath=none \ -p 32 -i ~/.ssh/id_ed25519 \ -L 9200:127.0.0.1:9200 root@127.0.0.1 curl -s http://127.0.0.1:9200/ # 7.16.3 curl -s 'http://127.0.0.1:9200/_cat/indices?h=index,docs.count' ``` `ControlMaster=no / ControlPath=none` обязательны — иначе forward уходит в persistent master из `~/.ssh/config`. - Индекс `files_file` (~39.8k док-в), `_count` ОК. - **Факты live поправили формулировку issue:** поля не `tenant_id`/`folder_id`, а `tenantId` (integer) и `folders[].folderId` (строка). Контент — `document.attachment.content`; заполняется **только для Office-форматов** (docx/xlsx/pptx), у PDF/txt, залитых через API, контента нет. - `title` analyzer `whitespacecustom` — режет по пробелам/lower-case, полное имя файла = один токен. REST `@search` по-прежнему только по имени в БД. ### Реализация - `file_es.go`: `ESSearcher` — прямой ES REST на stdlib `net/http` (без новых зависимостей). `Search(SearchQuery)`: - `multi_match` по `title^2`; при `InContent` + `document.attachment.content`; - фильтр `tenantId` (env `ONLYOFFICE_TENANT`) и `folders.folderId`; - `_source` id/title/folders, `highlight` (теги `<em>` срезаются); - возвращает `[]SearchHit`; `Name() = "elasticsearch"`. - Модель `Entry`/`Kind`/`SearchHit`/`SearchQuery`/`Searcher` — из F1 #35; пока объявлена в `file_es.go` (F1 ещё не влит), при мерже переезжает в `file_core.go` — согласуем. - Конфиг: `ONLYOFFICE_ES_URL`, `ONLYOFFICE_ES_INDEX` (default `files_file`), `ONLYOFFICE_TENANT`. `.env.example` — только имена. - CLI `oo search <query> [--content] [--folder id] [--limit N] [--json]` — тонкая обёртка через `printTable`/`printJSON`. - `docs/elasticsearch.md`: устройство поиска, схема полей, туннель, env, грабли (анализ title, контент только Office, async-индексация). ### Тесты (имена + PASS) - Unit `file_es_test.go`: `TestESSearchRequestNameOnly`, `TestESSearchRequestContentFields`, `TestESSearchRequestFiltersAndLimit`, `TestNewESSearcherRequiresURL`, `TestNormalizeExtensions`, `TestParseESSearchResponse`, `TestESSearchRequestJSONShape` — PASS. - CLI `cmd/oo/search_test.go`: `TestSearchCommandRegisteredWithFlags`, `TestSearchWithoutESURLIsClearError` — PASS. - Integration `file_es_integration_test.go` (`//go:build integration`, skip без `ONLYOFFICE_ES_URL`): `TestIntegrationESSearch` — заливает временный xlsx (уникальные токены в имени и в ячейке), ждёт асинхронной индексации, находит по имени и по контенту, проверяет highlight и что name-only поиск не находит content-токен, затем удаляет проект. **PASS live** (туннель). - `go build ./... && go vet ./... && go test -race ./...` — зелёные. gitleaks — `no leaks found`. Секретов в коде нет. Примечание: `go vet -tags=integration ./...` падает на **чужом** файле `cmd/office/fetch/task_integration_test.go:60` (`loader.TaskFields undefined`) — существует на `main`, к PR не относится. ### Блокеры Нет. ES доступен через SSH-туннель; на постоянку его можно завернуть в systemd-юнит (как `vado-vision-tunnel`) — отдельная инфра-задача.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: eSlider/go-onlyoffice#37