Files
go-onlyoffice/docs/elasticsearch.md
T
eSlider 33b5c1ea97
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 1.25) (pull_request) Successful in 18s
Tests / Test (Go stable) (pull_request) Successful in 20s
feat(search): Elasticsearch searcher (name+content) and oo search (#37)
2026-09-16 16:42:06 +00:00

5.3 KiB
Raw Blame History

type, status, related
type status related
reference current
README.md
file_es.go

Elasticsearch — полнотекстовый поиск OnlyOffice

Что это

Полнотекстовый поиск OnlyOffice Workspace работает на Elasticsearch. Клиент на сервере — NEST. Индекс — имя таблицы.

Для файлов индекс files_file:

поле тип смысл
id integer id файла (тот же, что в REST/Documents)
title text (whitespacecustom) имя файла
tenantId integer тенант (портал)
folders nested список папок: folderId (строка), id, tenantId
document.attachment.content text (document) извлеченный текст (ingest-attachment)
document.attachment.content_type text MIME

Важно:

  • Живой сервер — Elasticsearch 7.16.3, кластер elasticsearch.
  • REST GET /api/2.0/files/@search/{query} ищет только по имени в БД (fileDao.Search), ES не задействует. Для поиска по содержимому нужен прямой ES — это и делает oo search.
  • title analyzer whitespacecustom режет по пробелам и lower-case. Полное имя файла — один токен (Rechnung-4711.pdf), поэтому поиск по имени ищет слово целиком, а не подстроку.
  • document.attachment.content заполняется только для Office-форматов (docx / xlsx / pptx). У PDF/txt, залитых через API, контент не извлекается.
  • Индексация асинхронная (TeamLabSvc) — файл появляется в ES не мгновенно.

Доступ

ES слушает 127.0.0.1:9200 внутри VM OnlyOffice. Снаружи порт закрыт, SSH в VM открыт на хосте как 127.0.0.1:32 (контейнер onlyoffice-v2, QEMU). Схема — SSH-туннель.

# из корня go-onlyoffice (ключ и хост — как в infra-доках)
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/ | head            # tagline + version
curl -s 'http://127.0.0.1:9200/_cat/indices?h=index,docs.count'

-o ControlMaster=no -o ControlPath=none обязательны: иначе forward уходит в persistent master-соединение из ~/.ssh/config и порт остаётся занят.

Проверить, что туннель жив:

curl -s http://127.0.0.1:9200/files_file/_count

Переменные

env default смысл
ONLYOFFICE_ES_URL — (обязателен) scheme://host:port ES
ONLYOFFICE_ES_INDEX files_file индекс
ONLYOFFICE_TENANT пусто (все) фильтр tenantId

Имена — в .env.example. Секретов нет: ES без пароля.

CLI

ONLYOFFICE_ES_URL=http://127.0.0.1:9200 oo search "Rechnung"
ONLYOFFICE_ES_URL=http://127.0.0.1:9200 oo search "Mahngebühr" --content
oo search "Rechnung" --folder 649 --limit 50 --json

Флаги: --content (искать и по тексту), --folder ID (папка folders.folderId), --limit N (по умолчанию 20, максимум 200), --json = -o json.

Библиотека

file_es.go — ESSearcher (Name() = "elasticsearch"), прямой ES REST на stdlib net/http:

es, _ := onlyoffice.NewESSearcher(onlyoffice.ESConfigFromEnv())
hits, _ := es.Search(ctx, onlyoffice.SearchQuery{
    Text: "Rechnung", InContent: true, Limit: 20,
})

Запрос: multi_match по title^2 (+ document.attachment.content при InContent), фильтры tenantId и folders.folderId, _source id/title/folders, highlight для фрагмента. Ответ → []SearchHit (модель из эпика #34; пока объявлена в file_es.go, переедет в file_core.go с F1 #35).

Тесты

# unit — чистые builders/парсеры, без сети
go test ./ -run ES

# integration — нужен ONLYOFFICE_ES_URL (+ креды REST для залива)
set -a; . .env; set +a
ONLYOFFICE_ES_URL=http://127.0.0.1:9200 ONLYOFFICE_TENANT=1 \
  go test -tags=integration -run TestIntegrationESSearch -v .

Интеграционный тест заливает временный xlsx (в имени и в ячейке — уникальные токены), ждёт индексации, проверяет поиск по имени и по содержимому, затем удаляет проект.

Грабли

  • locale/версия ES: 7.16.3, _search совместим с REST 7.x.
  • ES без auth и слушает только localhost — туннель обязателен.
  • Фильтр tenantId сузит выдачу; без него видны документы всех тенантов.
  • Поиск по содержимому PDF, залитых через API, не работает (нет attachment.content) — только Office-форматы.