From 8f4f0e4efc127c027b4137a7628da98910cc158f Mon Sep 17 00:00:00 2001 From: Shinsuke Sugaya Date: Sun, 4 Oct 2026 16:16:05 +0900 Subject: [PATCH] docs(15.9): add the operating facts of the chunk job, embedding settings and engine-side fusion Add what the 15.9 semantic search pages left out or got wrong. Each statement was checked against the Fess source. rank-fusion: - With engine-side fusion the total hit count and the facet counts cover the union of the keyword and semantic hits. With Fess-side fusion the count is the main searcher's count plus a correction of at most window_size / 2, and the facets are the main searcher's. - A page whose start is at or beyond rank.fusion.pagination_depth is refused (HTTP 400 invalid_request in the v2 search API). - An unresponsive embedding provider delays an engine-fused search by its timeout times its attempts, since rank.fusion.timeout does not apply. search-semantic: - content_chunker.embedding.dimension: an unset value gives a 768-dimension mapping without any warning (the page said it warned) that cannot be changed afterwards. New section on the failure that follows and how to recover. - content_chunk_status: which documents become skipped, including every document when content_chunker.chunker.name names no chunker; skipped and fail are terminal; how to read the status distribution as the state of the chunk job. - content_chunker.embedding.opensearch.retry.max is the number of attempts, not the number of retries. - content_chunker.search.knn.k is per shard, and with Fess-side fusion it has a floor of window_size divided by the number of searchers. - chunk_size is in characters while the model's limit is in tokens (measured example for paraphrase-multilingual-MiniLM-L12-v2). - Changing to another model of the same dimension is accepted silently and mixes vector spaces; how to switch. api-search: - q is limited by api.param.max.length (default 1000); a longer value returns 400 invalid_request. All seven languages, 15.9 tree only. --- de/15.9/api/api-search.rst | 2 +- de/15.9/config/rank-fusion.rst | 31 +++++-- de/15.9/config/search-semantic.rst | 115 +++++++++++++++++++++++--- en/15.9/api/api-search.rst | 2 +- en/15.9/config/rank-fusion.rst | 29 +++++-- en/15.9/config/search-semantic.rst | 105 ++++++++++++++++++++--- es/15.9/api/api-search.rst | 2 +- es/15.9/config/rank-fusion.rst | 27 ++++-- es/15.9/config/search-semantic.rst | 110 ++++++++++++++++++++++-- fr/15.9/api/api-search.rst | 2 +- fr/15.9/config/rank-fusion.rst | 26 ++++-- fr/15.9/config/search-semantic.rst | 114 ++++++++++++++++++++++--- ja/15.9/api/api-search.rst | 2 +- ja/15.9/config/rank-fusion.rst | 22 +++-- ja/15.9/config/search-semantic.rst | 100 +++++++++++++++++++--- ko/15.9/api/api-search.rst | 2 +- ko/15.9/config/rank-fusion.rst | 22 +++-- ko/15.9/config/search-semantic.rst | 96 +++++++++++++++++++-- zh-cn/15.9/api/api-search.rst | 2 +- zh-cn/15.9/config/rank-fusion.rst | 18 +++- zh-cn/15.9/config/search-semantic.rst | 85 +++++++++++++++++-- 21 files changed, 802 insertions(+), 112 deletions(-) diff --git a/de/15.9/api/api-search.rst b/de/15.9/api/api-search.rst index b57e7338..46784dc7 100644 --- a/de/15.9/api/api-search.rst +++ b/de/15.9/api/api-search.rst @@ -30,7 +30,7 @@ Anfrageparameter .. list-table:: Anfrageparameter * - ``q`` - - Suchbegriff (URL-kodiert). + - Suchbegriff (URL-kodiert). Die maximale Länge wird durch ``api.param.max.length`` (Standardwert 1000) begrenzt. Bei Überschreitung wird ein ``invalid_request``-Fehler (HTTP 400) zurückgegeben. Diese Begrenzung ist unabhängig von den Limits der Suchmaschine. * - ``start`` - Startposition (0-basiert; integer, ``>=0``, Standardwert ``0``). * - ``offset`` diff --git a/de/15.9/config/rank-fusion.rst b/de/15.9/config/rank-fusion.rst index 03a848e5..b525965f 100644 --- a/de/15.9/config/rank-fusion.rst +++ b/de/15.9/config/rank-fusion.rst @@ -237,17 +237,23 @@ Beachten Sie Folgendes, wenn die Suchmaschine die Fusion durchführt. - ``rank.fusion.timeout`` gilt nicht. Das Embedding der Anfrage wird synchron berechnet, bevor die Suchanfrage gesendet wird; ein langsamer oder nicht antwortender Embedding-Anbieter verzögert die Suche daher bis zum Timeout des Anbieters selbst (zum Beispiel - ``content_chunker.embedding.ollama.timeout``). + ``content_chunker.embedding.ollama.timeout``). Wiederholt der Anbieter Anfragen, verlängern die + Wiederholungen diese Zeit. Der integrierte Anbieter ``opensearch`` wiederholt zum Beispiel + das Warten von ``content_chunker.embedding.opensearch.timeout`` (Standardwert ``60000`` ms) bis + zu ``content_chunker.embedding.opensearch.retry.max`` (Standardwert ``3``) Mal, sodass ein nicht + antwortender Anbieter eine Suche standardmäßig um 180 Sekunden plus die Wartezeiten zwischen + den Wiederholungen verzögern kann. - ``rank.fusion.window_size`` und ``rank.fusion.threads`` werden nur verwendet, wenn |Fess| die Fusion durchführt. - Eine fusionierte Suche kann höchstens ``rank.fusion.pagination_depth`` Ergebnisse durchblättern, weil die Suchmaschine nur die ersten ``rank.fusion.pagination_depth`` Ergebnisse jedes Suchers pro Shard fusioniert. Seitenanzahl, Link zur nächsten Seite und Seitennummern enden dort, und eine - Seite, die dahinter beginnt, wird mit demselben Fehler abgelehnt wie bei jeder anderen Suche eine - Seite jenseits von ``index.max_result_window``. Eine Seite, die nach dem letzten fusionierten - Ergebnis, aber innerhalb dieser Grenze beginnt (zum Beispiel über einen veralteten Link), wird - leer zurückgegeben. Suchen, die nicht in der Suchmaschine fusioniert werden, lassen sich wie - bisher bis ``index.max_result_window`` durchblättern. + Seite, deren Startposition (``start``) ``rank.fusion.pagination_depth`` oder mehr beträgt, wird + mit demselben Fehler abgelehnt wie bei jeder anderen Suche eine Seite jenseits von + ``index.max_result_window`` (in der Such-API v2 HTTP 400 mit ``invalid_request``). Eine Seite, + die nach dem letzten fusionierten Ergebnis, aber innerhalb dieser Grenze beginnt (zum Beispiel + über einen veralteten Link), wird leer zurückgegeben. Suchen, die nicht in der Suchmaschine + fusioniert werden, lassen sich wie bisher bis ``index.max_result_window`` durchblättern. - Die Gesamttrefferzahl ist exakt, solange sie unter ``rank.fusion.pagination_depth`` liegt. Ab diesem Wert kann die Suchmaschine weniger Treffer zählen, als tatsächlich übereinstimmen; die Zahl wird daher als Untergrenze gemeldet (in der Such-API ist ``record_count_relation`` dann @@ -333,8 +339,17 @@ Hybridsuche aktiviert ist oder nicht. Wird die Gesamttrefferzahl des Hauptsuchers als Näherungswert (Untergrenze) zurückgegeben, findet diese Korrektur nicht statt. -Führt die Suchmaschine die Fusion durch, ist die Gesamttrefferzahl die der fusionierten -Ergebnismenge (siehe :ref:`rank-fusion-engine`). +Die Facettenzahlen (Labels usw.) werden ebenfalls unverändert aus den Ergebnissen des +Hauptsuchers übernommen. + +Führt die Suchmaschine die Fusion durch (siehe :ref:`rank-fusion-engine`), umfassen die +Gesamttrefferzahl und die Facettenzahlen die Vereinigungsmenge der Treffer von Schlüsselwortsuche +und semantischer Suche. Jeder Sucher liefert höchstens ``rank.fusion.pagination_depth`` +Ergebnisse pro Shard, und der semantische Sucher ist zusätzlich auf +``content_chunker.search.knn.k`` begrenzt. Daher meldet dieselbe Anfrage je nach +``rank.fusion.engine.enabled`` unterschiedliche Trefferzahlen und Facettenzahlen, und bei einem +kleinen Index fallen sie tendenziell größer aus, wenn die Suchmaschine die Fusion durchführt, weil +die semantische Suche ihre Treffer beisteuert. Anwendungsbeispiele =================== diff --git a/de/15.9/config/search-semantic.rst b/de/15.9/config/search-semantic.rst index 5c797ff4..1b4358fd 100644 --- a/de/15.9/config/search-semantic.rst +++ b/de/15.9/config/search-semantic.rst @@ -180,12 +180,16 @@ Einstellungen in system.properties - Dimension des Embedding-Vektors. Dieser Wert wird bei der Erstellung des Mappings verwendet und **muss** daher mit der Dimension des verwendeten Embedding-Modells übereinstimmen. Für diesen Wert gibt es zwei Lesepfade, die sich unterschiedlich verhalten. - Bei der Erstellung des Index-Mappings wird mit einer Warnung ``768`` verwendet, wenn der - Wert nicht gesetzt, nicht-numerisch, nicht positiv oder größer als ``16000`` (das Maximum - des k-NN-Plugins selbst) ist. Zur Laufzeit des Embedding-Prozesses gibt es dagegen keinen + Bei der Erstellung des Index-Mappings wird ``768`` **ohne jede Warnung** verwendet, wenn + der Wert nicht gesetzt ist; ist er leer, nicht-numerisch, nicht positiv oder größer als + ``16000`` (das Maximum des k-NN-Plugins selbst), wird mit einer Warnung ``768`` verwendet. + Zur Laufzeit des Embedding-Prozesses gibt es dagegen keinen Fallback: nicht gesetzte, nicht-numerische und nicht positive Werte führen jeweils zu einem Fehler. Werte über ``16000`` werden zur Laufzeit nicht abgelehnt, sodass nur das Mapping - mit ``768`` erstellt wird und es zu einer Dimensionsabweichung kommt + mit ``768`` erstellt wird und es zu einer Dimensionsabweichung kommt. Die Dimension des + Mappings lässt sich nach der Erstellung des Index nicht mehr ändern; zur Behebung bei einem + Index, der ohne gesetzten Wert erstellt wurde, siehe *Wenn der Index ohne Dimension + erstellt wurde* unter *Hinweise* * - ``content_chunker.job.concurrency`` - ``2`` - Anzahl paralleler Worker für den Indexer-Job @@ -233,9 +237,10 @@ Einstellungen in system.properties eine Änderung erfordert die Neuerstellung des Index) * - ``content_chunker.search.knn.k`` - ``100`` - - Anzahl der pro ANN-Abfrage abgerufenen Nachbarn (wird für Deep Paging automatisch - vergrößert, wenn |Fess| die Fusion durchführt; unverändert verwendet, wenn die Suchmaschine - die Fusion durchführt) + - Anzahl der pro Shard von der ANN-Abfrage abgerufenen Nachbarn. Führt |Fess| die Fusion + durch, fällt der wirksame Wert nie unter ``rank.fusion.window_size`` geteilt durch die + Anzahl der Sucher (standardmäßig 200 / 2 = 100); ein kleinerer Wert hat daher keine + Wirkung. Führt die Suchmaschine die Fusion durch, wird dieser Wert unverändert verwendet * - ``content_chunker.search.knn.param.ef_search`` - (nicht gesetzt) - Der Parameter ``ef_search`` für ANN-Abfragen @@ -264,6 +269,17 @@ Einstellungen in system.properties gechunkte Dokumente aus: Ein bereits als Chunk-Array gespeichertes Dokument behält seine Grenzen, bis es erneut gecrawlt wird. +.. note:: + + ``content_chunker.length.chunk_size`` wird in Zeichen angegeben, ein Embedding-Modell kann + aber nur Text bis zu seinem Token-Limit aufnehmen. |Fess| kürzt den eingebetteten Text nicht, + sodass der Teil jenseits dieses Limits möglicherweise nicht im Vektor berücksichtigt wird. + Wählen Sie ``chunk_size`` anhand des Eingabelimits des verwendeten Modells. Gemessen mit + ``paraphrase-multilingual-MiniLM-L12-v2`` (höchstens 128 Token) wurden beispielsweise etwa + 440 Zeichen englischer und etwa 210 Zeichen japanischer Text im Vektor berücksichtigt (je nach + Text unterschiedlich). Bei diesem Modell wird der hintere Teil eines Chunks mit dem Standardwert + ``chunk_size=800`` nicht im Vektor berücksichtigt. + .. note:: Die HNSW-Parameter ``m`` und ``ef_construction`` sind in ``doc.json`` fest codiert @@ -303,7 +319,10 @@ Diese werden in derselben Datei ``system.properties`` wie oben gesetzt. - Verbindungs-Timeout (ms) * - ``content_chunker.embedding.opensearch.retry.max`` - ``3`` - - Anzahl der Wiederholungen bei vorübergehenden Fehlern (429, 5xx usw.) + - Maximale Anzahl der Versuche einschließlich des ersten bei vorübergehenden Fehlern (429, + 5xx usw.). Das ist nicht die Anzahl der Wiederholungen: ``3`` bedeutet insgesamt höchstens + drei Anfragen mit zwei Wartezeiten dazwischen. Ein Wert von ``1`` oder weniger bedeutet + keine Wiederholung * - ``content_chunker.embedding.opensearch.retry.base.delay.ms`` - ``2000`` - Basisverzögerung für Wiederholungen (ms) @@ -514,9 +533,16 @@ Sie können das Ergebnis für jedes Dokument in dessen Feld ``content_chunk_stat ebenso, wenn das Plugin des unter ``embedding.name`` angegebenen Anbieters nicht installiert ist * - ``skipped`` - - Verarbeitung übersprungen (z. B. ``max_chunks_per_document`` überschritten) + - Verarbeitung übersprungen. Das betrifft Dokumente mit leerem Text (auch nur aus + Leerzeichen), Dokumente, für die kein Chunk erzeugt wurde, und Dokumente, die + ``max_chunks_per_document`` überschreiten. Nennt ``content_chunker.chunker.name`` einen + nicht vorhandenen Chunker, wird kein Chunker gefunden und kein Chunk erzeugt; dann landen + alle Dokumente in diesem Zustand. Es ist ein Endzustand: Ein erneuter Job-Lauf verarbeitet + das Dokument nicht noch einmal * - ``fail`` - - Verarbeitung fehlgeschlagen (Protokolle prüfen) + - Verarbeitung fehlgeschlagen (Protokolle prüfen). Es ist ein Endzustand: Standardmäßig + verarbeitet ein erneuter Job-Lauf das Dokument nicht noch einmal. Setzen Sie + ``content_chunker.job.retry_failed`` auf ``true``, um es erneut zu verarbeiten Sie können die Verteilung der Statuswerte durch eine direkte Abfrage der Suchmaschine prüfen:: @@ -527,6 +553,32 @@ Sie können die Verteilung der Statuswerte durch eine direkte Abfrage der Suchma Durch die Option ``missing`` werden Dokumente ohne ``content_chunk_status`` (also unverarbeitete Dokumente) in einem Bucket mit dem Schlüssel ``pending`` zusammengefasst. +Beurteilen Sie den Zustand des Chunk-Jobs anhand dieser Verteilung von ``content_chunk_status``. +Wenn ``pending`` mit jedem Job-Lauf kleiner und ``done`` (im Nur-Chunk-Modus ``chunked``) größer +wird, macht der Job Fortschritte. Taucht ``fail`` auf, prüfen Sie die |Fess|-Protokolle auf die +Ursache. ``skipped`` ist bei Dokumenten wie solchen mit leerem Text normal; sind aber fast alle +Dokumente ``skipped``, vermuten Sie einen falschen Wert für ``content_chunker.chunker.name`` +(wird kein Chunker gefunden, wird eine WARN-Meldung ``Chunker not found`` protokolliert). + +.. warning:: + + Das Korrigieren der Konfiguration macht ``skipped`` oder ``fail`` nicht von selbst rückgängig. + Ein Dokument mit ``skipped`` wird bei einem erneuten Job-Lauf nicht aufgenommen (ein erneut + gecrawltes Dokument kehrt in den unverarbeiteten Zustand zurück), und ein Dokument mit ``fail`` + wird nur dann erneut verarbeitet, wenn ``content_chunker.job.retry_failed`` auf ``true`` steht. + Lief der Job zum Beispiel mit einem falschen ``content_chunker.chunker.name`` und alle + Dokumente wurden ``skipped``, korrigieren Sie den Namen, löschen Sie ``content_chunk_status`` + wie unten gezeigt und führen Sie den Job danach erneut aus (das Feld ``content`` eines + ``skipped``-Dokuments wurde nicht überschrieben, daher kann es unverändert verarbeitet + werden):: + + curl -XPOST "http://localhost:9200/fess.search/_update_by_query" \ + -H "Content-Type: application/json" -d ' + { + "query": {"term": {"content_chunk_status": "skipped"}}, + "script": {"source": "ctx._source.remove(\"content_chunk_status\")"} + }' + Verhalten der semantischen Suche ==================================== @@ -845,6 +897,49 @@ Reihenfolge vor. bestehenden Installation)* unter *Einrichtungsverfahren* neu und führen Sie den Indexer-Job erneut aus. +Wechsel zu einem anderen Modell mit gleicher Dimension +--------------------------------------------------------- + +Ändern Sie die Embedding-Modelleinstellung, etwa +``content_chunker.embedding.opensearch.model.id``, auf ein anderes Modell mit derselben +Dimension, akzeptiert |Fess| das ohne Fehler oder Warnung. Geprüft wird nur die Dimension; das +Modell, das die Vektoren erzeugt hat, wird im Index nicht festgehalten. Die gespeicherten +Vektoren stammen dann vom alten Modell und die Abfragevektoren bei der Suche vom neuen; beide +liegen in verschiedenen Vektorräumen, sodass die Relevanz der Suchergebnisse zusammenbricht. +Auch die Verteilung der Kosinus-Ähnlichkeitswerte unterscheidet sich von Modell zu Modell, sodass +ein auf das alte Modell abgestimmtes ``content_chunker.search.min_score`` für das neue Modell zu +streng sein kann und die meisten Ergebnisse abschneidet. + +Um das Modell zu wechseln, setzen Sie das neue Modell, löschen Sie ``content_chunk_vector`` und +``content_chunk_status`` mit demselben ``_update_by_query`` wie in Schritt 1 von *Das +Embedding-Modell (Dimension) wechseln* oben und führen Sie den Indexer-Job erneut aus, um die +Vektoren aller Dokumente neu zu erzeugen (der Index muss nicht neu erstellt werden, weil die +Dimension gleich ist). Haben Sie ``content_chunker.search.min_score`` gesetzt, überprüfen Sie +den Wert mit dem neuen Modell. + +Wenn der Index ohne Dimension erstellt wurde +--------------------------------------------- + +Wird der Index ``fess.search`` erstellt, während ``content_chunker.embedding.dimension`` nicht +gesetzt ist, erhält das Mapping von ``content_chunk_vector`` ohne jede Warnung die Dimension +``768``, und sie lässt sich danach nicht mehr ändern. Führen Sie dann den Indexer-Job aus, lässt +sich die Dimension beim Embedding nicht lesen, was ein Fehler ist, sodass die Dokumente ``fail`` +werden. + +- Hat das verwendete Modell die Dimension ``768``, setzen Sie + ``content_chunker.embedding.dimension=768``. Sie stimmt mit dem Mapping überein, der Index + muss also nicht neu erstellt werden. +- Andernfalls setzen Sie die richtige Dimension. Solange Mapping (``768``) und Einstellung + voneinander abweichen, protokolliert der Indexer-Job einen ERROR und überspringt den Lauf. + Erstellen Sie den Index nach derselben Methode wie in Schritt 3 von *Das Embedding-Modell + (Dimension) wechseln* oben neu. + +In beiden Fällen werden Dokumente, die bereits ``fail`` sind, nicht automatisch erneut +verarbeitet. Erstellen Sie den Index neu, löscht das ``_update_by_query`` in Schritt 1 von *Das +Embedding-Modell (Dimension) wechseln* auch ``content_chunk_status``. Erstellen Sie ihn nicht neu, +setzen Sie ``content_chunker.job.retry_failed`` vorübergehend auf ``true`` und führen Sie den Job +erneut aus. + Festplattennutzung --------------------- diff --git a/en/15.9/api/api-search.rst b/en/15.9/api/api-search.rst index 8e665d23..1e018367 100644 --- a/en/15.9/api/api-search.rst +++ b/en/15.9/api/api-search.rst @@ -30,7 +30,7 @@ Request Parameters .. list-table:: Request Parameters * - ``q`` - - Search term (URL-encoded). + - Search term (URL-encoded). The maximum length is limited by ``api.param.max.length`` (default 1000). Exceeding it results in an ``invalid_request`` error (HTTP 400). This limit is separate from the search engine's own limits. * - ``start`` - Zero-based start position (integer, ``>=0``, default ``0``). * - ``offset`` diff --git a/en/15.9/config/rank-fusion.rst b/en/15.9/config/rank-fusion.rst index a7a446a7..35246e9c 100644 --- a/en/15.9/config/rank-fusion.rst +++ b/en/15.9/config/rank-fusion.rst @@ -229,16 +229,22 @@ Keep the following in mind when the search engine performs the fusion. - ``rank.fusion.timeout`` does not apply. The query embedding is computed synchronously before the search request is sent, so a slow or unresponsive embedding provider delays the search up to the - provider's own timeout (for example ``content_chunker.embedding.ollama.timeout``). + provider's own timeout (for example ``content_chunker.embedding.ollama.timeout``). If the + provider retries, the retries add to that time. For example, the built-in ``opensearch`` + provider repeats a wait of ``content_chunker.embedding.opensearch.timeout`` (default ``60000`` + ms) up to ``content_chunker.embedding.opensearch.retry.max`` (default ``3``) times, so an + unresponsive provider can delay a search by 180 seconds by default, plus the waits between + retries. - ``rank.fusion.window_size`` and ``rank.fusion.threads`` are used only when |Fess| performs the fusion. - A fused search pages through at most ``rank.fusion.pagination_depth`` results, because the search engine fuses only the top ``rank.fusion.pagination_depth`` results of each searcher per - shard. The page count, the next-page link and the page numbers stop there, and a page that - starts beyond it is refused with the same error as a page beyond ``index.max_result_window`` in - any other search. A page that starts after the last fused result but within that limit (for - example, from an outdated link) is returned empty. Searches that are not fused in the search - engine page up to ``index.max_result_window`` as before. + shard. The page count, the next-page link and the page numbers stop there, and a page whose + start position (``start``) is ``rank.fusion.pagination_depth`` or more is refused with the same + error as a page beyond ``index.max_result_window`` in any other search (in the v2 search API, + HTTP 400 with ``invalid_request``). A page that starts after the last fused result but within + that limit (for example, from an outdated link) is returned empty. Searches that are not fused + in the search engine page up to ``index.max_result_window`` as before. - The total hit count is exact while it is below ``rank.fusion.pagination_depth``. At or above it, the search engine can count fewer hits than actually match, so the count is reported as a lower bound (in the search API, ``record_count_relation`` is ``GREATER_THAN_OR_EQUAL_TO``). @@ -315,8 +321,15 @@ enabled. Note that this adjustment is not applied when the total hit count of the main searcher is returned as an approximate (lower-bound) value. -When the search engine performs the fusion, the total hit count is that of the fused result set -(see :ref:`rank-fusion-engine`). +The facet counts (labels and so on) are also taken from the main searcher's results as they are. + +When the search engine performs the fusion (see :ref:`rank-fusion-engine`), the total hit count +and the facet counts cover the union of the hits of both keyword search and semantic search. Each +searcher contributes at most ``rank.fusion.pagination_depth`` results per shard, and the semantic +searcher is further limited to ``content_chunker.search.knn.k``. As a result, the same query +reports different counts and facet counts depending on ``rank.fusion.engine.enabled``, and on a +small index they tend to be larger when the search engine performs the fusion, because semantic +search contributes its hits. Usage Examples ============== diff --git a/en/15.9/config/search-semantic.rst b/en/15.9/config/search-semantic.rst index 76e183d8..0fb454f7 100644 --- a/en/15.9/config/search-semantic.rst +++ b/en/15.9/config/search-semantic.rst @@ -175,11 +175,14 @@ system.properties Settings - Dimension of the embedding vector. This value is used when the mapping is created, so it **must** match the dimension of the embedding model you use. There are two distinct read paths for this value, and they behave differently. When the index mapping is created, an - unset, non-numeric, non-positive, or above-``16000`` value (``16000`` is the k-NN plugin's - own maximum) falls back to ``768`` with a warning. The embedding process itself, by - contrast, has no fallback: an unset, non-numeric, or non-positive value is an error there. - A value above ``16000`` is not rejected at runtime, so only the mapping ends up at ``768`` - and you get a dimension mismatch + unset value falls back to ``768`` **without any warning**, and an empty, non-numeric, + non-positive, or above-``16000`` value (``16000`` is the k-NN plugin's own maximum) falls + back to ``768`` with a warning. The embedding process itself, by contrast, has no + fallback: an unset, non-numeric, or non-positive value is an error there. A value above + ``16000`` is not rejected at runtime, so only the mapping ends up at ``768`` and you get a + dimension mismatch. The mapping's dimension cannot be changed once the index has been + created; see *If the Index Was Created Without a Dimension* under *Notes* for how to + recover from an index created with the value unset * - ``content_chunker.job.concurrency`` - ``2`` - Number of parallel workers for the indexer job @@ -224,8 +227,10 @@ system.properties Settings requires recreating the index) * - ``content_chunker.search.knn.k`` - ``100`` - - Number of neighbors retrieved per ANN query (automatically enlarged for deep paging when - |Fess| performs the fusion; used as is when the search engine performs the fusion) + - Number of neighbors retrieved per shard by the ANN query. When |Fess| performs the fusion, + the effective value never falls below ``rank.fusion.window_size`` divided by the number of + searchers (200 / 2 = 100 by default), so a smaller value has no effect. When the search + engine performs the fusion, this value is used as is * - ``content_chunker.search.knn.param.ef_search`` - (unset) - The ``ef_search`` parameter for ANN queries @@ -251,6 +256,17 @@ system.properties Settings affects documents chunked afterwards: a document already stored as a chunk array keeps its boundaries until it is re-crawled. +.. note:: + + ``content_chunker.length.chunk_size`` is specified in characters, but an embedding model can + only take in text up to its token limit. |Fess| does not truncate the text it embeds, so the + part beyond that limit may not be reflected in the vector. Choose ``chunk_size`` from the + input limit of the model you use. For example, measured with + ``paraphrase-multilingual-MiniLM-L12-v2`` (128 tokens at most), the part that was reflected + in the vector was about 440 characters of English and about 210 characters of Japanese (it + varies with the text). With this model, the later part of a chunk at the default + ``chunk_size=800`` is not reflected in the vector. + .. note:: The HNSW ``m`` and ``ef_construction`` parameters are hard-coded in ``doc.json`` @@ -289,7 +305,9 @@ set in the same ``system.properties`` file as above. - Connection timeout (ms) * - ``content_chunker.embedding.opensearch.retry.max`` - ``3`` - - Number of retries for transient errors (429, 5xx, etc.) + - Maximum number of attempts, including the first, for transient errors (429, 5xx, etc.). + This is not the number of retries: ``3`` means at most three requests in total, with two + waits in between. A value of ``1`` or less means no retry * - ``content_chunker.embedding.opensearch.retry.base.delay.ms`` - ``2000`` - Base retry backoff delay (ms) @@ -485,9 +503,15 @@ You can check the outcome for each document in its ``content_chunk_status`` fiel ``embedding.name=none``, and also when the plugin for the provider named in ``embedding.name`` is not installed * - ``skipped`` - - Processing skipped (e.g. exceeded ``max_chunks_per_document``) + - Processing skipped. This covers documents whose body is empty (including whitespace + only), documents for which no chunk was produced, and documents that exceed + ``max_chunks_per_document``. If ``content_chunker.chunker.name`` names a chunker that does + not exist, no chunker is found and no chunk is produced, so every document ends up in this + state. It is a terminal state: re-running the job does not process the document again * - ``fail`` - - Processing failed (check the logs) + - Processing failed (check the logs). It is a terminal state: by default, re-running the job + does not process the document again. Set ``content_chunker.job.retry_failed`` to ``true`` + to process it again You can check the distribution of statuses by querying the search engine directly:: @@ -498,6 +522,30 @@ You can check the distribution of statuses by querying the search engine directl Thanks to the ``missing`` option, documents that have no ``content_chunk_status`` (that is, unprocessed documents) are aggregated into a bucket keyed ``pending``. +Judge the state of the chunk job by this distribution of ``content_chunk_status``. If ``pending`` +shrinks and ``done`` (``chunked`` in chunk-only mode) grows with each job run, the job is making +progress. If ``fail`` appears, check the |Fess| logs for the cause. ``skipped`` is normal for +documents such as those with an empty body, but if nearly every document is ``skipped``, suspect a +wrong ``content_chunker.chunker.name`` (when no chunker is found, a ``Chunker not found`` WARN +message is logged). + +.. warning:: + + Fixing the configuration does not by itself undo ``skipped`` or ``fail``. A ``skipped`` + document is not picked up when the job is re-run (a re-crawled document returns to the + unprocessed state), and a ``fail`` document is processed again only when + ``content_chunker.job.retry_failed`` is ``true``. For example, if the job ran with a wrong + ``content_chunker.chunker.name`` and every document became ``skipped``, correct the name, + delete ``content_chunk_status`` as shown below, and then re-run the job (a ``skipped`` + document's ``content`` has not been rewritten, so it can be processed as it is):: + + curl -XPOST "http://localhost:9200/fess.search/_update_by_query" \ + -H "Content-Type: application/json" -d ' + { + "query": {"term": {"content_chunk_status": "skipped"}}, + "script": {"source": "ctx._source.remove(\"content_chunk_status\")"} + }' + How Semantic Search Behaves ============================== @@ -788,6 +836,43 @@ To switch to an embedding model with a different dimension, follow this order. 3. Recreate the index as described in *3. Recreate the Index (When Enabling on an Existing Deployment)* under *Setup Procedure*, then re-run the indexer job. +Changing to Another Model with the Same Dimension +--------------------------------------------------- + +If you change the embedding model setting, such as +``content_chunker.embedding.opensearch.model.id``, to another model with the same dimension, +|Fess| accepts it without any error or warning. Only the dimension is checked, and the model +that created the vectors is not recorded in the index. The stored vectors were then created by +the old model and the query vectors at search time by the new one; the two live in different +vector spaces, so the relevance of search results breaks down. The distribution of cosine +similarity values also differs from model to model, so a ``content_chunker.search.min_score`` +tuned for the old model can be too strict for the new one and cut off most results. + +To switch models, set the new model, delete ``content_chunk_vector`` and ``content_chunk_status`` +with the same ``_update_by_query`` as in step 1 of *Changing the Embedding Model (Dimension)* +above, and re-run the indexer job to regenerate the vectors of every document (the index does not +need to be recreated, because the dimension is the same). If you have set +``content_chunker.search.min_score``, review it with the new model. + +If the Index Was Created Without a Dimension +--------------------------------------------- + +If the ``fess.search`` index is created while ``content_chunker.embedding.dimension`` is unset, +the ``content_chunk_vector`` mapping gets a dimension of ``768`` without any warning, and it +cannot be changed afterwards. If you then run the indexer job, the dimension cannot be read when +embedding, which is an error, so the documents become ``fail``. + +- If the model you use has a dimension of ``768``, set ``content_chunker.embedding.dimension=768``. + It matches the mapping, so the index does not need to be recreated. +- Otherwise, set the correct dimension. While the mapping (``768``) and the setting disagree, the + indexer job logs an ERROR and skips the run. Recreate the index by the same method as in step 3 + of *Changing the Embedding Model (Dimension)* above. + +In either case, documents that have already become ``fail`` are not processed again +automatically. If you recreate the index, the ``_update_by_query`` in step 1 of *Changing the +Embedding Model (Dimension)* also deletes ``content_chunk_status``. If you do not recreate it, +temporarily set ``content_chunker.job.retry_failed`` to ``true`` and re-run the job. + Disk Usage ------------ diff --git a/es/15.9/api/api-search.rst b/es/15.9/api/api-search.rst index 15b8fe5c..9d3ba394 100644 --- a/es/15.9/api/api-search.rst +++ b/es/15.9/api/api-search.rst @@ -30,7 +30,7 @@ Parámetros de solicitud .. list-table:: Parámetros de solicitud * - ``q`` - - Término de búsqueda (codificado en URL). + - Término de búsqueda (codificado en URL). La longitud máxima está limitada por ``api.param.max.length`` (valor predeterminado: 1000). Si se supera, se produce un error ``invalid_request`` (HTTP 400). Este límite es independiente de los límites del motor de búsqueda. * - ``start`` - Posición de inicio desde 0 (integer, ``>=0``, valor predeterminado ``0``). * - ``offset`` diff --git a/es/15.9/config/rank-fusion.rst b/es/15.9/config/rank-fusion.rst index 2f28c3a7..9c2f999b 100644 --- a/es/15.9/config/rank-fusion.rst +++ b/es/15.9/config/rank-fusion.rst @@ -236,14 +236,21 @@ Tenga en cuenta lo siguiente cuando la fusión la realiza el motor de búsqueda. - ``rank.fusion.timeout`` no se aplica. El embedding de la consulta se calcula de forma síncrona antes de enviar la solicitud de búsqueda, por lo que un proveedor de embeddings lento o que no responde retrasa la búsqueda hasta el tiempo de espera propio del proveedor (por ejemplo, - ``content_chunker.embedding.ollama.timeout``). + ``content_chunker.embedding.ollama.timeout``). Si el proveedor reintenta, los reintentos se + suman a ese tiempo. Por ejemplo, el proveedor integrado ``opensearch`` repite una espera de + ``content_chunker.embedding.opensearch.timeout`` (``60000`` ms de forma predeterminada) hasta + ``content_chunker.embedding.opensearch.retry.max`` (``3`` de forma predeterminada) veces, por + lo que un proveedor que no responde puede retrasar una búsqueda 180 segundos de forma + predeterminada, más las esperas entre reintentos. - ``rank.fusion.window_size`` y ``rank.fusion.threads`` solo se utilizan cuando la fusión la realiza |Fess|. - Una búsqueda fusionada puede paginar como máximo ``rank.fusion.pagination_depth`` resultados, porque el motor de búsqueda solo fusiona los primeros ``rank.fusion.pagination_depth`` resultados de cada buscador por shard. El número de páginas, el enlace a la página siguiente y - los números de página se detienen ahí, y una página que empieza más allá se rechaza con el mismo - error que, en cualquier otra búsqueda, una página más allá de ``index.max_result_window``. Una + los números de página se detienen ahí, y una página cuya posición inicial (``start``) es + ``rank.fusion.pagination_depth`` o mayor se rechaza con el mismo error que, en cualquier otra + búsqueda, una página más allá de ``index.max_result_window`` (en la API de búsqueda v2, HTTP 400 + con ``invalid_request``). Una página que empieza después del último resultado fusionado pero dentro de ese límite (por ejemplo, desde un enlace obsoleto) se devuelve vacía. Las búsquedas que no se fusionan en el motor de búsqueda pueden paginar hasta ``index.max_result_window``, como antes. @@ -331,8 +338,18 @@ híbrida está habilitada o no. Tenga en cuenta que, si el número total de resultados del buscador principal se devuelve como un valor aproximado (un límite inferior), esta corrección no se aplica. -Cuando la fusión la realiza el motor de búsqueda, el número total de resultados es el del conjunto -de resultados fusionado (consulte :ref:`rank-fusion-engine`). +Los recuentos de facetas (etiquetas, etc.) también se toman tal cual de los resultados del buscador +principal. + +Cuando la fusión la realiza el motor de búsqueda (consulte :ref:`rank-fusion-engine`), el número +total de resultados y los recuentos de facetas abarcan la unión de los resultados de la búsqueda +por palabras clave y de la búsqueda semántica. Cada buscador aporta como máximo +``rank.fusion.pagination_depth`` resultados por shard, y el buscador semántico está limitado +además por ``content_chunker.search.knn.k``. Por ello, una misma consulta informa un número +total de resultados y unos recuentos de facetas distintos según ``rank.fusion.engine.enabled``, y +en un índice pequeño suelen +ser mayores cuando la fusión la realiza el motor de búsqueda, porque la búsqueda semántica aporta +sus resultados. Ejemplos de uso =============== diff --git a/es/15.9/config/search-semantic.rst b/es/15.9/config/search-semantic.rst index f708e7bc..bc942038 100644 --- a/es/15.9/config/search-semantic.rst +++ b/es/15.9/config/search-semantic.rst @@ -182,12 +182,15 @@ Configuraciones en system.properties - Dimensión del vector de embedding. Este valor se utiliza al crear el mapeo, por lo que **debe** coincidir con la dimensión del modelo de embedding que utilice. Este valor tiene dos rutas de lectura, con comportamientos distintos. Al crear el mapeo del índice, si el - valor no está establecido, no es numérico, es 0 o negativo, o supera ``16000`` (el máximo - propio del plugin k-NN), se aplica ``768`` con una advertencia. En cambio, al ejecutar el + valor no está establecido se aplica ``768`` **sin ninguna advertencia**, y si está vacío, + no es numérico, es 0 o negativo, o supera ``16000`` (el máximo propio del plugin k-NN), se + aplica ``768`` con una advertencia. En cambio, al ejecutar el proceso de embedding no hay ningún valor de respaldo: un valor sin establecer, no numérico o 0 o negativo produce un error. Un valor superior a ``16000`` no se rechaza en tiempo de ejecución, por lo que solo el mapeo acaba creado con ``768`` y se produce un desajuste de - dimensión + dimensión. La dimensión del mapeo no se puede cambiar una vez creado el índice; para + recuperarse de un índice creado con el valor sin establecer, consulte *Si el índice se creó + sin dimensión* en *Notas* * - ``content_chunker.job.concurrency`` - ``2`` - Número de workers paralelos para el trabajo del indexador @@ -234,9 +237,10 @@ Configuraciones en system.properties en el mapeo; cambiarlo requiere recrear el índice) * - ``content_chunker.search.knn.k`` - ``100`` - - Número de vecinos recuperados por consulta ANN (se amplía automáticamente para paginación - profunda cuando la fusión la realiza |Fess|; se usa tal cual cuando la fusión la realiza el - motor de búsqueda) + - Número de vecinos recuperados por shard en la consulta ANN. Cuando la fusión la realiza + |Fess|, el valor efectivo nunca baja de ``rank.fusion.window_size`` dividido por el número + de buscadores (200 / 2 = 100 de forma predeterminada), por lo que un valor menor no tiene + efecto. Cuando la fusión la realiza el motor de búsqueda, este valor se usa tal cual * - ``content_chunker.search.knn.param.ef_search`` - (sin establecer) - El parámetro ``ef_search`` para las consultas ANN @@ -264,6 +268,17 @@ Configuraciones en system.properties ajustes solo afecta a los documentos divididos a partir de ese momento: un documento ya almacenado como array de chunks conserva sus límites hasta que se vuelve a rastrear. +.. note:: + + ``content_chunker.length.chunk_size`` se especifica en caracteres, pero un modelo de embedding + solo puede asimilar texto hasta su límite de tokens. |Fess| no trunca el texto sometido al + embedding, por lo que la parte que supera ese límite puede no quedar reflejada en el vector. + Elija ``chunk_size`` según el límite de entrada del modelo que utilice. Por ejemplo, medido + con ``paraphrase-multilingual-MiniLM-L12-v2`` (128 tokens como máximo), la parte reflejada en + el vector fue de unos 440 caracteres en inglés y unos 210 caracteres en japonés (varía según + el texto). Con este modelo, la parte final de un chunk con el valor predeterminado + ``chunk_size=800`` no queda reflejada en el vector. + .. note:: Los parámetros HNSW ``m`` y ``ef_construction`` están codificados de forma fija en @@ -304,7 +319,10 @@ Estos se establecen en el mismo archivo ``system.properties`` que se indicó ant - Tiempo de espera de conexión (ms) * - ``content_chunker.embedding.opensearch.retry.max`` - ``3`` - - Número de reintentos para errores transitorios (429, 5xx, etc.) + - Número máximo de intentos, incluido el primero, para errores transitorios (429, 5xx, + etc.). No es el número de reintentos: ``3`` significa como máximo tres solicitudes en + total, con dos esperas entre ellas. Un valor de ``1`` o menor significa que no hay + reintento * - ``content_chunker.embedding.opensearch.retry.base.delay.ms`` - ``2000`` - Retraso base de reintento (ms) @@ -516,9 +534,16 @@ Puede verificar el resultado de cada documento en su campo ``content_chunk_statu ``embedding.name=none``, este estado también se produce cuando el plugin del proveedor indicado en ``embedding.name`` no está instalado * - ``skipped`` - - Procesamiento omitido (p. ej., se superó ``max_chunks_per_document``) + - Procesamiento omitido. Incluye los documentos cuyo cuerpo está vacío (también si solo + contiene espacios en blanco), los documentos para los que no se generó ningún chunk y los + que superan ``max_chunks_per_document``. Si ``content_chunker.chunker.name`` indica un + chunker que no existe, no se encuentra ningún chunker y no se genera ningún chunk, por lo + que todos los documentos acaban en este estado. Es un estado terminal: volver a ejecutar + el trabajo no vuelve a procesar el documento * - ``fail`` - - Procesamiento fallido (revise los registros) + - Procesamiento fallido (revise los registros). Es un estado terminal: de forma + predeterminada, volver a ejecutar el trabajo no vuelve a procesar el documento. Establezca + ``content_chunker.job.retry_failed`` en ``true`` para procesarlo de nuevo Puede verificar la distribución de estados consultando directamente el motor de búsqueda:: @@ -529,6 +554,32 @@ Puede verificar la distribución de estados consultando directamente el motor de Gracias a la opción ``missing``, los documentos que no tienen ``content_chunk_status`` (es decir, los que aún no se han procesado) se agrupan en un bucket con la clave ``pending``. +Evalúe el estado del trabajo de chunking según esta distribución de ``content_chunk_status``. Si +``pending`` disminuye y ``done`` (``chunked`` en el modo solo chunking) aumenta con cada +ejecución del trabajo, el trabajo avanza. Si aparece ``fail``, revise los registros de |Fess| +para conocer la causa. ``skipped`` es normal para documentos como los de cuerpo vacío, pero si +casi todos los documentos están en ``skipped``, sospeche de un valor incorrecto de +``content_chunker.chunker.name`` (cuando no se encuentra ningún chunker, se registra un mensaje +WARN ``Chunker not found``). + +.. warning:: + + Corregir la configuración no revierte por sí solo ``skipped`` ni ``fail``. Un documento + ``skipped`` no se recoge al volver a ejecutar el trabajo (un documento rastreado de nuevo + vuelve al estado sin procesar), y un documento ``fail`` solo se procesa de nuevo cuando + ``content_chunker.job.retry_failed`` es ``true``. Por ejemplo, si el trabajo se ejecutó con un + ``content_chunker.chunker.name`` incorrecto y todos los documentos pasaron a ``skipped``, + corrija el nombre, elimine ``content_chunk_status`` como se muestra a continuación y vuelva a + ejecutar el trabajo (el campo ``content`` de un documento ``skipped`` no se ha reescrito, por + lo que se puede procesar tal cual):: + + curl -XPOST "http://localhost:9200/fess.search/_update_by_query" \ + -H "Content-Type: application/json" -d ' + { + "query": {"term": {"content_chunk_status": "skipped"}}, + "script": {"source": "ctx._source.remove(\"content_chunk_status\")"} + }' + Comportamiento de la búsqueda semántica ========================================== @@ -844,6 +895,47 @@ Para cambiar a un modelo de embedding con una dimensión diferente, siga este or 3. Recree el índice siguiendo *3. Recrear el índice (al habilitar en una instalación existente)* del *Procedimiento de configuración*, y vuelva a ejecutar el trabajo del indexador. +Cambio a otro modelo con la misma dimensión +---------------------------------------------- + +Si cambia la configuración del modelo de embedding, como +``content_chunker.embedding.opensearch.model.id``, a otro modelo con la misma dimensión, |Fess| +lo acepta sin ningún error ni advertencia. Solo se comprueba la dimensión, y el modelo que +creó los vectores no se registra en el índice. Los vectores almacenados fueron creados entonces +por el modelo antiguo y los vectores de consulta, al buscar, por el nuevo; ambos viven en +espacios vectoriales distintos, por lo que la relevancia de los resultados de búsqueda se +degrada. La distribución de los valores de similitud del coseno también difiere de un modelo a +otro, por lo que un ``content_chunker.search.min_score`` ajustado para el modelo antiguo puede +resultar demasiado estricto para el nuevo y descartar la mayoría de los resultados. + +Para cambiar de modelo, configure el nuevo modelo, elimine ``content_chunk_vector`` y +``content_chunk_status`` con el mismo ``_update_by_query`` del paso 1 de *Cambiar el modelo de +embedding (dimensión)* más arriba, y vuelva a ejecutar el trabajo del indexador para regenerar +los vectores de todos los documentos (no es necesario recrear el índice, porque la dimensión es +la misma). Si ha establecido ``content_chunker.search.min_score``, revíselo con el nuevo modelo. + +Si el índice se creó sin dimensión +------------------------------------ + +Si el índice ``fess.search`` se crea mientras ``content_chunker.embedding.dimension`` no está +establecido, el mapeo de ``content_chunk_vector`` recibe una dimensión de ``768`` sin ninguna +advertencia, y no se puede cambiar después. Si a continuación ejecuta el trabajo del indexador, +no se puede leer la dimensión al generar los embeddings, lo cual es un error, por lo que los +documentos pasan a ``fail``. + +- Si el modelo que utiliza tiene una dimensión de ``768``, establezca + ``content_chunker.embedding.dimension=768``. Coincide con el mapeo, por lo que no es necesario + recrear el índice. +- En caso contrario, establezca la dimensión correcta. Mientras el mapeo (``768``) y el valor + configurado discrepen, el trabajo del indexador registra un ERROR y omite la ejecución. Recree + el índice con el mismo método del paso 3 de *Cambiar el modelo de embedding (dimensión)* más + arriba. + +En ambos casos, los documentos que ya están en ``fail`` no se vuelven a procesar +automáticamente. Si recrea el índice, el ``_update_by_query`` del paso 1 de *Cambiar el modelo de +embedding (dimensión)* también elimina ``content_chunk_status``. Si no lo recrea, establezca +temporalmente ``content_chunker.job.retry_failed`` en ``true`` y vuelva a ejecutar el trabajo. + Uso de disco -------------- diff --git a/fr/15.9/api/api-search.rst b/fr/15.9/api/api-search.rst index cf72c4fa..6e30d6d3 100644 --- a/fr/15.9/api/api-search.rst +++ b/fr/15.9/api/api-search.rst @@ -30,7 +30,7 @@ Paramètres de requête .. list-table:: Paramètres de requête * - ``q`` - - Terme de recherche (encodé en URL). + - Terme de recherche (encodé en URL). La longueur maximale est limitée par ``api.param.max.length`` (valeur par défaut 1000). La dépasser entraîne une erreur ``invalid_request`` (HTTP 400). Cette limite est distincte de celles du moteur de recherche. * - ``start`` - Position de départ à base zéro (entier, ``>=0``, valeur par défaut ``0``). * - ``offset`` diff --git a/fr/15.9/config/rank-fusion.rst b/fr/15.9/config/rank-fusion.rst index e5bc1f4c..24f2c4f3 100644 --- a/fr/15.9/config/rank-fusion.rst +++ b/fr/15.9/config/rank-fusion.rst @@ -241,14 +241,21 @@ Gardez les points suivants à l'esprit lorsque la fusion est effectuée côté m - ``rank.fusion.timeout`` ne s'applique pas. L'embedding de la requête est calculé de manière synchrone avant l'envoi de la requête de recherche : un fournisseur d'embedding lent ou qui ne répond pas retarde donc la recherche jusqu'au délai d'expiration propre à ce fournisseur (par - exemple ``content_chunker.embedding.ollama.timeout``). + exemple ``content_chunker.embedding.ollama.timeout``). Si le fournisseur effectue de nouvelles + tentatives, elles s'ajoutent à ce délai. Par exemple, le fournisseur intégré ``opensearch`` + répète une attente de ``content_chunker.embedding.opensearch.timeout`` (``60000`` ms par + défaut) jusqu'à ``content_chunker.embedding.opensearch.retry.max`` (``3`` par défaut) fois : + un fournisseur qui ne répond pas peut donc retarder une recherche de 180 secondes par défaut, + plus les attentes entre les tentatives. - ``rank.fusion.window_size`` et ``rank.fusion.threads`` ne sont utilisés que lorsque |Fess| effectue la fusion. - Une recherche fusionnée peut paginer au plus ``rank.fusion.pagination_depth`` résultats, car le moteur de recherche ne fusionne que les ``rank.fusion.pagination_depth`` premiers résultats de chaque moteur, par shard. Le nombre de pages, le lien vers la page suivante et les numéros de - page s'arrêtent là, et une page qui commence au-delà est refusée avec la même erreur qu'une page - au-delà de ``index.max_result_window`` pour toute autre recherche. Une page qui commence après le + page s'arrêtent là, et une page dont la position de départ (``start``) vaut + ``rank.fusion.pagination_depth`` ou plus est refusée avec la même erreur qu'une page au-delà + de ``index.max_result_window`` pour toute autre recherche (dans l'API de recherche v2, HTTP 400 + avec ``invalid_request``). Une page qui commence après le dernier résultat fusionné mais dans cette limite (par exemple depuis un lien périmé) est renvoyée vide. Les recherches qui ne sont pas fusionnées côté moteur de recherche peuvent toujours paginer jusqu'à ``index.max_result_window``. @@ -336,8 +343,17 @@ recherche hybride est activée ou non. À noter : lorsque le nombre total de résultats du moteur principal est retourné sous forme de valeur approchée (borne inférieure), cette correction n'est pas appliquée. -Lorsque la fusion est effectuée côté moteur de recherche, le nombre total de résultats est celui de -l'ensemble de résultats fusionné (voir :ref:`rank-fusion-engine`). +Les nombres de résultats des facettes (étiquettes, etc.) sont eux aussi repris tels quels des +résultats du moteur principal. + +Lorsque la fusion est effectuée côté moteur de recherche (voir :ref:`rank-fusion-engine`), le +nombre total de résultats et les nombres de résultats des facettes portent sur l'union des +résultats de la recherche par mots-clés et de la recherche sémantique. Chaque moteur apporte au +plus ``rank.fusion.pagination_depth`` résultats par shard, et le moteur sémantique est en outre +limité par ``content_chunker.search.knn.k``. Pour une même requête, le nombre total de résultats +et ceux des facettes diffèrent donc selon ``rank.fusion.engine.enabled`` ; sur un petit index, ils +tendent à être plus élevés lorsque la fusion est effectuée côté moteur de recherche, car la +recherche sémantique apporte ses résultats. Exemples d'utilisation ======================= diff --git a/fr/15.9/config/search-semantic.rst b/fr/15.9/config/search-semantic.rst index 3a3d0a2b..3d45babe 100644 --- a/fr/15.9/config/search-semantic.rst +++ b/fr/15.9/config/search-semantic.rst @@ -185,12 +185,16 @@ Réglages dans system.properties - Dimension du vecteur d'embedding. Cette valeur est utilisée lors de la création du mapping, elle **doit** donc correspondre à la dimension du modèle d'embedding utilisé. Elle est lue par deux chemins distincts, au comportement différent. Lors de la création du - mapping de l'index, une valeur non définie, non numérique, nulle ou négative, ou - supérieure à ``16000`` (le maximum propre au plugin k-NN) entraîne l'utilisation de - ``768`` avec un avertissement. À l'exécution du processus d'embedding, en revanche, il n'y + mapping de l'index, une valeur non définie entraîne l'utilisation de ``768`` **sans aucun + avertissement**, et une valeur vide, non numérique, nulle ou négative, ou supérieure à + ``16000`` (le maximum propre au plugin k-NN) entraîne l'utilisation de ``768`` avec un + avertissement. À l'exécution du processus d'embedding, en revanche, il n'y a aucun repli : une valeur non définie, non numérique, nulle ou négative provoque une erreur. Une valeur supérieure à ``16000`` n'est pas rejetée à l'exécution, de sorte que - seul le mapping est créé avec ``768``, ce qui aboutit à une incohérence de dimension + seul le mapping est créé avec ``768``, ce qui aboutit à une incohérence de dimension. La + dimension du mapping ne peut plus être modifiée une fois l'index créé ; pour vous remettre + d'un index créé alors que la valeur n'était pas définie, voir *Si l'index a été créé sans + dimension* dans *Remarques* * - ``content_chunker.job.concurrency`` - ``2`` - Nombre de workers parallèles pour la tâche d'indexation @@ -238,9 +242,11 @@ Réglages dans system.properties mapping ; le modifier nécessite de recréer l'index) * - ``content_chunker.search.knn.k`` - ``100`` - - Nombre de voisins récupérés par requête ANN (agrandi automatiquement pour la pagination - profonde lorsque |Fess| effectue la fusion ; utilisé tel quel lorsque la fusion est - effectuée côté moteur de recherche) + - Nombre de voisins récupérés par shard par la requête ANN. Lorsque |Fess| effectue la + fusion, la valeur effective ne descend jamais sous ``rank.fusion.window_size`` divisé par + le nombre de moteurs (200 / 2 = 100 par défaut) ; une valeur plus petite n'a donc aucun + effet. Lorsque la fusion est effectuée côté moteur de recherche, cette valeur est + utilisée telle quelle * - ``content_chunker.search.knn.param.ef_search`` - (non défini) - Le paramètre ``ef_search`` pour les requêtes ANN @@ -269,6 +275,17 @@ Réglages dans system.properties paramètres n'affecte que les documents découpés ensuite : un document déjà stocké sous forme de tableau de chunks conserve ses frontières jusqu'à ce qu'il soit à nouveau crawlé. +.. note:: + + ``content_chunker.length.chunk_size`` s'exprime en caractères, mais un modèle d'embedding ne + peut prendre en compte qu'un texte allant jusqu'à sa limite de tokens. |Fess| ne tronque pas le + texte soumis à l'embedding ; la partie au-delà de cette limite peut donc ne pas être reflétée + dans le vecteur. Choisissez ``chunk_size`` d'après la limite d'entrée du modèle utilisé. Par + exemple, mesurée avec ``paraphrase-multilingual-MiniLM-L12-v2`` (128 tokens au maximum), la + partie reflétée dans le vecteur était d'environ 440 caractères en anglais et d'environ 210 + caractères en japonais (cela varie selon le texte). Avec ce modèle, la fin d'un chunk avec la + valeur par défaut ``chunk_size=800`` n'est pas reflétée dans le vecteur. + .. note:: Les paramètres HNSW ``m`` et ``ef_construction`` sont codés en dur dans ``doc.json`` @@ -308,7 +325,10 @@ Ceux-ci sont définis dans le même fichier ``system.properties`` que ci-dessus. - Délai d'expiration de connexion (ms) * - ``content_chunker.embedding.opensearch.retry.max`` - ``3`` - - Nombre de nouvelles tentatives pour les erreurs transitoires (429, 5xx, etc.) + - Nombre maximal de tentatives, première incluse, pour les erreurs transitoires (429, 5xx, + etc.). Ce n'est pas le nombre de nouvelles tentatives : ``3`` signifie au plus trois + requêtes au total, avec deux attentes entre elles. Une valeur de ``1`` ou moins signifie + aucune nouvelle tentative * - ``content_chunker.embedding.opensearch.retry.base.delay.ms`` - ``2000`` - Délai de base entre les tentatives (ms) @@ -518,9 +538,16 @@ Vous pouvez vérifier le résultat pour chaque document dans son champ ``content ``embedding.name=none``, mais aussi lorsque le plugin du fournisseur indiqué dans ``embedding.name`` n'est pas installé * - ``skipped`` - - Traitement ignoré (par ex. ``max_chunks_per_document`` dépassé) + - Traitement ignoré. Cela concerne les documents dont le corps est vide (y compris + uniquement des espaces), les documents pour lesquels aucun chunk n'a été produit et ceux + qui dépassent ``max_chunks_per_document``. Si ``content_chunker.chunker.name`` désigne un + chunker inexistant, aucun chunker n'est trouvé et aucun chunk n'est produit : tous les + documents se retrouvent alors dans cet état. C'est un état terminal : relancer la tâche ne + retraite pas le document * - ``fail`` - - Échec du traitement (vérifiez les journaux) + - Échec du traitement (vérifiez les journaux). C'est un état terminal : par défaut, relancer + la tâche ne retraite pas le document. Définissez ``content_chunker.job.retry_failed`` à + ``true`` pour le retraiter Vous pouvez vérifier la répartition des statuts en interrogeant directement le moteur de recherche :: @@ -532,6 +559,32 @@ recherche :: Grâce à l'option ``missing``, les documents dépourvus de ``content_chunk_status`` (autrement dit non traités) sont regroupés dans un bucket portant la clé ``pending``. +Jugez de l'état de la tâche de chunking d'après cette répartition de ``content_chunk_status``. Si +``pending`` diminue et ``done`` (``chunked`` en mode chunking seul) augmente à chaque exécution de +la tâche, celle-ci progresse. Si ``fail`` apparaît, consultez les journaux de |Fess| pour en +trouver la cause. ``skipped`` est normal pour des documents tels que ceux dont le corps est vide, +mais si presque tous les documents sont ``skipped``, soupçonnez une valeur erronée de +``content_chunker.chunker.name`` (lorsqu'aucun chunker n'est trouvé, un message WARN +``Chunker not found`` est journalisé). + +.. warning:: + + Corriger la configuration n'annule pas à lui seul ``skipped`` ni ``fail``. Un document + ``skipped`` n'est pas pris en charge lorsque la tâche est relancée (un document crawlé à + nouveau revient à l'état non traité), et un document ``fail`` n'est retraité que si + ``content_chunker.job.retry_failed`` vaut ``true``. Par exemple, si la tâche a été exécutée + avec un ``content_chunker.chunker.name`` erroné et que tous les documents sont devenus + ``skipped``, corrigez le nom, supprimez ``content_chunk_status`` comme indiqué ci-dessous, + puis relancez la tâche (le champ ``content`` d'un document ``skipped`` n'a pas été réécrit ; + il peut donc être traité tel quel) :: + + curl -XPOST "http://localhost:9200/fess.search/_update_by_query" \ + -H "Content-Type: application/json" -d ' + { + "query": {"term": {"content_chunk_status": "skipped"}}, + "script": {"source": "ctx._source.remove(\"content_chunk_status\")"} + }' + Comportement de la recherche sémantique ========================================== @@ -850,6 +903,47 @@ Pour passer à un modèle d'embedding avec une dimension différente, suivez cet 3. Recréez l'index en suivant *3. Recréer l'index (lors de l'activation sur un déploiement existant)* dans *Procédure de configuration*, puis relancez la tâche d'indexation. +Passer à un autre modèle de même dimension +--------------------------------------------- + +Si vous remplacez le réglage du modèle d'embedding, par exemple +``content_chunker.embedding.opensearch.model.id``, par un autre modèle de même dimension, |Fess| +l'accepte sans aucune erreur ni avertissement. Seule la dimension est vérifiée, et le modèle qui +a créé les vecteurs n'est pas enregistré dans l'index. Les vecteurs stockés ont alors été créés +par l'ancien modèle et les vecteurs de requête, lors de la recherche, par le nouveau ; les deux +vivent dans des espaces vectoriels différents, et la pertinence des résultats de recherche +s'effondre. La distribution des valeurs de similarité cosinus diffère aussi d'un modèle à +l'autre : un ``content_chunker.search.min_score`` réglé pour l'ancien modèle peut être trop +strict pour le nouveau et écarter la plupart des résultats. + +Pour changer de modèle, définissez le nouveau modèle, supprimez ``content_chunk_vector`` et +``content_chunk_status`` avec le même ``_update_by_query`` que dans l'étape 1 de *Changer de +modèle d'embedding (dimension)* ci-dessus, puis relancez la tâche d'indexation pour régénérer les +vecteurs de tous les documents (il n'est pas nécessaire de recréer l'index, car la dimension est +la même). Si vous avez défini ``content_chunker.search.min_score``, réexaminez-le avec le nouveau +modèle. + +Si l'index a été créé sans dimension +-------------------------------------- + +Si l'index ``fess.search`` est créé alors que ``content_chunker.embedding.dimension`` n'est pas +défini, le mapping de ``content_chunk_vector`` reçoit une dimension de ``768`` sans aucun +avertissement, et elle ne peut plus être modifiée ensuite. Si vous exécutez alors la tâche +d'indexation, la dimension ne peut pas être lue lors de l'embedding, ce qui est une erreur : les +documents passent à ``fail``. + +- Si le modèle utilisé a une dimension de ``768``, définissez + ``content_chunker.embedding.dimension=768``. Elle correspond au mapping ; il n'est donc pas + nécessaire de recréer l'index. +- Sinon, définissez la bonne dimension. Tant que le mapping (``768``) et le réglage divergent, + la tâche d'indexation journalise une ERROR et ignore l'exécution. Recréez l'index selon la même + méthode que dans l'étape 3 de *Changer de modèle d'embedding (dimension)* ci-dessus. + +Dans les deux cas, les documents déjà à l'état ``fail`` ne sont pas retraités automatiquement. Si +vous recréez l'index, le ``_update_by_query`` de l'étape 1 de *Changer de modèle d'embedding +(dimension)* supprime aussi ``content_chunk_status``. Si vous ne le recréez pas, définissez +temporairement ``content_chunker.job.retry_failed`` à ``true`` et relancez la tâche. + Utilisation du disque ------------------------ diff --git a/ja/15.9/api/api-search.rst b/ja/15.9/api/api-search.rst index 90c5e54c..86d6b9ac 100644 --- a/ja/15.9/api/api-search.rst +++ b/ja/15.9/api/api-search.rst @@ -30,7 +30,7 @@ HTTPメソッド GET .. list-table:: リクエストパラメーター * - ``q`` - - 検索語(URLエンコード)。 + - 検索語(URLエンコード)。最大文字数は ``api.param.max.length`` (既定値 1000)で制限されます。超過した場合は ``invalid_request`` エラー(HTTP 400)になります。この制限は検索エンジンの制限とは別のものです。 * - ``start`` - 0始まりの開始位置(integer, ``>=0`` , 既定値 ``0`` )。 * - ``offset`` diff --git a/ja/15.9/config/rank-fusion.rst b/ja/15.9/config/rank-fusion.rst index 325310f0..dbf172d7 100644 --- a/ja/15.9/config/rank-fusion.rst +++ b/ja/15.9/config/rank-fusion.rst @@ -221,14 +221,19 @@ JVMシステムプロパティ - ``rank.fusion.timeout`` は適用されません。クエリの埋め込みは検索リクエストの送信前に同期的に 計算されるため、埋め込みプロバイダの応答が遅い場合や応答しない場合は、検索がプロバイダ側の - タイムアウト(例: ``content_chunker.embedding.ollama.timeout``)まで待たされます。 + タイムアウト(例: ``content_chunker.embedding.ollama.timeout``)まで待たされます。プロバイダが + 再試行する場合は、その回数分も加わります。たとえば内蔵の ``opensearch`` プロバイダは、 + ``content_chunker.embedding.opensearch.timeout``\ (既定 ``60000`` ミリ秒)の待機を + ``content_chunker.embedding.opensearch.retry.max``\ (既定 ``3``)回まで繰り返すため、 + 応答しない場合は既定で180秒に再試行の待機時間を加えた時間がかかることがあります。 - ``rank.fusion.window_size`` と ``rank.fusion.threads`` は、|Fess| 側で融合する場合にのみ 使われます。 - 検索エンジン側で融合した検索は、最大で ``rank.fusion.pagination_depth`` 件までページング できます。検索エンジンは各サーチャーのシャードごとの上位 ``rank.fusion.pagination_depth`` 件 - だけを融合するためです。ページ数、次ページの有無、ページ番号はこの件数で打ち切られ、これを - 超えた位置から始まるページを要求すると、ほかの検索で ``index.max_result_window`` を超えた - ページを要求した場合と同じエラーになります。この範囲内でも、融合結果の最後の件より後から + だけを融合するためです。ページ数、次ページの有無、ページ番号はこの件数で打ち切られ、開始位置 + (``start``)が ``rank.fusion.pagination_depth`` 以上のページを要求すると、ほかの検索で + ``index.max_result_window`` を超えたページを要求した場合と同じエラー(検索API v2 では + HTTP 400 の ``invalid_request``)になります。この範囲内でも、融合結果の最後の件より後から 始まるページ(古いリンクなど)は空のページになります。検索エンジン側で融合しない検索は、 これまでどおり ``index.max_result_window`` までページングできます。 - 総ヒット件数は ``rank.fusion.pagination_depth`` 未満であれば正確です。この値以上になると、 @@ -308,7 +313,14 @@ Rank Fusionが実際に動作しているかは、検索結果に付与される そのため、同じクエリでもハイブリッド検索の有効・無効でヒット件数が変わることがあります。 なお、メインサーチャーの総ヒット件数が概算値(下限値)として返される場合、この補正は行われません。 -検索エンジン側で融合する場合、総ヒット件数は融合後の結果集合の件数です(:ref:`rank-fusion-engine` を参照)。 +また、ファセット(ラベルなど)の件数はメインサーチャーの検索結果のものがそのまま使われます。 + +検索エンジン側で融合する場合(:ref:`rank-fusion-engine` を参照)、総ヒット件数とファセットの件数は、 +キーワード検索とセマンティック検索の両方のヒットの和集合を数えます。各サーチャーがシャードごとに +提供するのは最大で ``rank.fusion.pagination_depth`` 件で、セマンティックサーチャーはさらに +``content_chunker.search.knn.k`` 件が上限です。そのため、同じクエリでも ``rank.fusion.engine.enabled`` +を切り替えると件数もファセットの件数も変わり、小規模なインデックスでは、セマンティック検索が加わる +検索エンジン側で融合した場合のほうが大きくなりやすくなります。 使用例 ====== diff --git a/ja/15.9/config/search-semantic.rst b/ja/15.9/config/search-semantic.rst index afcf9b8d..22688d08 100644 --- a/ja/15.9/config/search-semantic.rst +++ b/ja/15.9/config/search-semantic.rst @@ -163,11 +163,13 @@ system.properties の設定 - ``768`` - 埋め込みベクトルの次元数。マッピング作成時にこの値が使われるため、使用する埋め込みモデルの 次元数に **必ず** 合わせて設定してください。この値には読み取り経路が2つあり、挙動が - 異なります。インデックスのマッピング作成時は、未設定・非数値・0 以下・``16000``\ (k-NN - プラグイン自体の上限)超のいずれでも、警告とともに ``768`` が使われます。一方、埋め込み - 処理の実行時にはフォールバックがなく、未設定・非数値・0 以下はいずれもエラーになります。 - ``16000`` を超える値は実行時には拒否されないため、マッピングだけが ``768`` で作成されて - 次元不一致になります + 異なります。インデックスのマッピング作成時は、未設定の場合は **警告なしで** ``768`` が + 使われ、空・非数値・0 以下・``16000``\ (k-NN プラグイン自体の上限)超の場合は警告とともに + ``768`` が使われます。一方、埋め込み処理の実行時にはフォールバックがなく、未設定・非数値・ + 0 以下はいずれもエラーになります。``16000`` を超える値は実行時には拒否されないため、 + マッピングだけが ``768`` で作成されて次元不一致になります。マッピングの次元数はインデックスの + 作成後に変更できません。未設定のまま作成してしまった場合の復旧は、後述の + 「次元数を設定せずにインデックスを作成した場合」を参照してください * - ``content_chunker.job.concurrency`` - ``2`` - インデクサジョブの並列数 @@ -210,8 +212,10 @@ system.properties の設定 インデックスの再作成が必要) * - ``content_chunker.search.knn.k`` - ``100`` - - ANNクエリで取得する近傍数(|Fess| 側で融合する場合、ページング範囲が大きいときは自動的に - 拡大。検索エンジン側で融合する場合はこの値がそのまま使われます) + - ANNクエリでシャードごとに取得する近傍数。|Fess| 側で融合する場合は + ``rank.fusion.window_size`` ÷ サーチャー数(既定では 200 ÷ 2 = 100)が下限になるため、 + それより小さい値には効果がありません。検索エンジン側で融合する場合は、この値がそのまま + 使われます * - ``content_chunker.search.knn.param.ef_search`` - (未設定) - ANNクエリの ``ef_search`` パラメーター @@ -237,6 +241,16 @@ system.properties の設定 以降にチャンク化されるドキュメントだけです。すでにチャンク配列として保存されている ドキュメントは、再クロールされるまで元の境界を保持します。 +.. note:: + + ``content_chunker.length.chunk_size`` は文字数で指定しますが、埋め込みモデルが一度に受け取れる + のはトークン数の上限までです。|Fess| は埋め込み対象のテキストを切り詰めないため、上限を超えた + 部分はベクトルに反映されないことがあります。``chunk_size`` は、使用するモデルの入力上限から + 選んでください。例えば ``paraphrase-multilingual-MiniLM-L12-v2``\ (最大128トークン)で実測した + ところ、ベクトルに反映された範囲は英語でおよそ440文字、日本語でおよそ210文字でした + (テキストによって変わります)。このモデルでは、既定の ``chunk_size=800`` のチャンクの + 後ろの部分はベクトルに反映されません。 + .. note:: HNSW の ``m`` と ``ef_construction`` パラメーターは ``doc.json`` に固定値 @@ -274,7 +288,8 @@ opensearch プロバイダの接続設定 - 接続タイムアウト(ミリ秒) * - ``content_chunker.embedding.opensearch.retry.max`` - ``3`` - - 一時的エラー(429/5xx等)のリトライ回数 + - 一時的エラー(429/5xx等)に対する最大試行回数(初回を含む)。リトライ回数ではありません。 + ``3`` なら最大3回リクエストし、その間の待機は2回です。``1`` 以下は再試行しません * - ``content_chunker.embedding.opensearch.retry.base.delay.ms`` - ``2000`` - リトライの基準待機時間(ミリ秒) @@ -465,9 +480,14 @@ Docker 版は ``/opt/fess/system.properties``。以下はすべて同じファ ``embedding.name`` に指定したプロバイダのプラグインが導入されていない場合もこの状態に なります * - ``skipped`` - - 処理をスキップ(``max_chunks_per_document`` 超過等) + - 処理をスキップ。本文が空(空白のみを含む)のドキュメント、チャンクが1つも生成されなかった + ドキュメント、``max_chunks_per_document`` を超えたドキュメントが該当します。 + ``content_chunker.chunker.name`` に存在しない名前を指定した場合も、チャンカーが見つからず + チャンクが生成されないため、すべてのドキュメントがこの状態になります。終端状態で、 + ジョブを再実行しても再処理されません * - ``fail`` - - 処理に失敗(ログを確認してください) + - 処理に失敗(ログを確認してください)。終端状態で、既定ではジョブを再実行しても再処理 + されません。再処理するには ``content_chunker.job.retry_failed`` を ``true`` にします 状態の分布は検索エンジンに直接問い合わせて確認できます:: @@ -478,6 +498,30 @@ Docker 版は ``/opt/fess/system.properties``。以下はすべて同じファ ``missing`` オプションにより、``content_chunk_status`` を持たない(=未処理の)ドキュメントは ``pending`` というキーのバケットに集計されます。 +チャンクジョブの状況は、この ``content_chunk_status`` の件数分布で判断してください。ジョブを実行する +たびに ``pending`` が減って ``done``\ (chunk-only モードでは ``chunked``)が増えていれば順調です。 +``fail`` が現れた場合は、|Fess| のログで原因を確認してください。``skipped`` は本文が空のドキュメント +などでは正常ですが、ほぼ全件が ``skipped`` になっている場合は ``content_chunker.chunker.name`` の +誤りを疑ってください(チャンカーが見つからない場合は ``Chunker not found`` というWARNログが出力 +されます)。 + +.. warning:: + + ``skipped`` と ``fail`` は、設定を直しただけでは元に戻りません。``skipped`` はジョブの再実行では + 選ばれず(再クロールされたドキュメントは未処理に戻ります)、``fail`` は + ``content_chunker.job.retry_failed`` を ``true`` にした場合にだけ再び処理対象になります。 + たとえば ``content_chunker.chunker.name`` を誤ったままジョブを実行して全件が ``skipped`` に + なった場合は、名前を直したうえで ``content_chunk_status`` を削除してから、ジョブを再実行して + ください(``skipped`` のドキュメントは ``content`` が書き換えられていないため、そのまま + 再処理できます):: + + curl -XPOST "http://localhost:9200/fess.search/_update_by_query" \ + -H "Content-Type: application/json" -d ' + { + "query": {"term": {"content_chunk_status": "skipped"}}, + "script": {"source": "ctx._source.remove(\"content_chunk_status\")"} + }' + セマンティック検索の動作 ======================== @@ -758,6 +802,42 @@ fess-webapp-semantic-search プラグインを利用していた場合 3. 「セットアップ手順」の「3. インデックスの再作成(既存の環境で有効化する場合)」に従って インデックスを再作成し、インデクサジョブを再実行します。 +同じ次元数の別モデルへの変更 +---------------------------- + +``content_chunker.embedding.opensearch.model.id`` など埋め込みモデルの設定を、次元数が同じ別の +モデルに変更しても、|Fess| はエラーも警告も出さずに受け付けます。検査されるのは次元数だけで、 +ベクトルを作成したモデルはインデックスに記録されないためです。この状態では、保存済みのベクトルは +旧モデル、検索時のクエリベクトルは新モデルで作られ、両者は別のベクトル空間にあるため、検索結果の +関連性が崩れます。また、コサイン類似度の値の分布はモデルごとに異なるため、旧モデルに合わせて調整した +``content_chunker.search.min_score`` が新モデルでは厳しすぎて、ほとんどの結果が足切りされることが +あります。 + +モデルを切り替えるときは、新しいモデルを設定したうえで、上記「埋め込みモデル(次元数)の変更」の +手順1と同じ ``_update_by_query`` で ``content_chunk_vector`` と ``content_chunk_status`` を削除し、 +インデクサジョブを再実行してすべてのドキュメントのベクトルを作り直してください(次元数が同じなので +インデックスの再作成は不要です)。``content_chunker.search.min_score`` を設定している場合は、 +新しいモデルで見直してください。 + +次元数を設定せずにインデックスを作成した場合 +-------------------------------------------- + +``content_chunker.embedding.dimension`` が未設定のまま ``fess.search`` インデックスを作成すると、 +``content_chunk_vector`` のマッピングは警告なしで ``768`` 次元になり、作成後は変更できません。 +この状態でインデクサジョブを実行すると、埋め込み処理の実行時には次元数を読み取れずエラーに +なるため、ドキュメントは ``fail`` になります。 + +- 使用するモデルの次元数が ``768`` の場合は、``content_chunker.embedding.dimension=768`` を設定 + します。マッピングと一致するため、インデックスの再作成は不要です。 +- ``768`` 以外の場合は、正しい次元数を設定します。マッピング(``768``)と設定値が食い違っている + 間、インデクサジョブは ERROR ログを出力して実行をスキップします。上記「埋め込みモデル + (次元数)の変更」の手順3と同じ方法でインデックスを再作成してください。 + +どちらの場合も、すでに ``fail`` になったドキュメントは自動では再処理されません。インデックスを +再作成する場合は、「埋め込みモデル(次元数)の変更」の手順1の ``_update_by_query`` が +``content_chunk_status`` も削除します。再作成しない場合は、``content_chunker.job.retry_failed`` を +一時的に ``true`` にしてジョブを再実行してください。 + ディスク使用量 -------------- diff --git a/ko/15.9/api/api-search.rst b/ko/15.9/api/api-search.rst index 3e5f799c..9aef81f2 100644 --- a/ko/15.9/api/api-search.rst +++ b/ko/15.9/api/api-search.rst @@ -30,7 +30,7 @@ HTTP 메서드 GET .. list-table:: 요청 파라미터 * - ``q`` - - 검색어 (URL 인코딩). + - 검색어 (URL 인코딩). 최대 문자 수는 ``api.param.max.length`` (기본값 1000) 로 제한됩니다. 초과한 경우 ``invalid_request`` 오류 (HTTP 400) 가 됩니다. 이 제한은 검색 엔진의 제한과는 별개입니다. * - ``start`` - 0 시작 시작 위치 (integer, ``>=0`` , 기본값 ``0`` ). * - ``offset`` diff --git a/ko/15.9/config/rank-fusion.rst b/ko/15.9/config/rank-fusion.rst index b868040e..346c58c4 100644 --- a/ko/15.9/config/rank-fusion.rst +++ b/ko/15.9/config/rank-fusion.rst @@ -223,14 +223,19 @@ JVM 시스템 프로퍼티 - ``rank.fusion.timeout`` 은 적용되지 않습니다. 쿼리 임베딩은 검색 요청을 보내기 전에 동기적으로 계산되므로, 임베딩 프로바이더의 응답이 느리거나 응답하지 않는 경우에는 검색이 프로바이더 측의 - 타임아웃(예: ``content_chunker.embedding.ollama.timeout``)까지 대기하게 됩니다. + 타임아웃(예: ``content_chunker.embedding.ollama.timeout``)까지 대기하게 됩니다. 프로바이더가 + 재시도하는 경우에는 그 횟수만큼도 더해집니다. 예를 들어 내장 ``opensearch`` 프로바이더는 + ``content_chunker.embedding.opensearch.timeout``\ (기본값 ``60000`` 밀리초)만큼의 대기를 + ``content_chunker.embedding.opensearch.retry.max``\ (기본값 ``3``)회까지 반복하므로, + 응답하지 않는 경우 기본값으로 180초에 재시도 사이의 대기 시간을 더한 시간이 걸릴 수 있습니다. - ``rank.fusion.window_size`` 와 ``rank.fusion.threads`` 는 |Fess| 측에서 융합하는 경우에만 사용됩니다. - 검색 엔진 측에서 융합한 검색은 최대 ``rank.fusion.pagination_depth`` 건까지 페이징할 수 있습니다. 검색 엔진은 각 검색기의 샤드별 상위 ``rank.fusion.pagination_depth`` 건만 융합하기 - 때문입니다. 페이지 수, 다음 페이지 여부, 페이지 번호는 이 건수에서 끝나며, 이를 넘는 위치에서 - 시작하는 페이지를 요청하면 다른 검색에서 ``index.max_result_window`` 를 넘는 페이지를 요청한 - 경우와 같은 오류가 됩니다. 이 범위 안이라도 융합 결과의 마지막 건 이후에서 시작하는 + 때문입니다. 페이지 수, 다음 페이지 여부, 페이지 번호는 이 건수에서 끝나며, 시작 위치 + (``start``)가 ``rank.fusion.pagination_depth`` 이상인 페이지를 요청하면 다른 검색에서 + ``index.max_result_window`` 를 넘는 페이지를 요청한 경우와 같은 오류(검색 API v2에서는 HTTP + 400의 ``invalid_request``)가 됩니다. 이 범위 안이라도 융합 결과의 마지막 건 이후에서 시작하는 페이지(오래된 링크 등)는 빈 페이지가 됩니다. 검색 엔진 측에서 융합하지 않는 검색은 지금까지와 마찬가지로 ``index.max_result_window`` 까지 페이징할 수 있습니다. - 총 히트 건수는 ``rank.fusion.pagination_depth`` 미만이면 정확합니다. 이 값 이상이 되면 검색 @@ -309,7 +314,14 @@ Rank Fusion이 실제로 동작하고 있는지는 검색 결과에 부여되는 그래서 같은 쿼리라도 하이브리드 검색의 활성화 여부에 따라 히트 건수가 달라질 수 있습니다. 또한 메인 검색기의 총 히트 건수가 개략값(하한값)으로 반환되는 경우에는 이 보정이 수행되지 않습니다. -검색 엔진 측에서 융합하는 경우, 총 히트 건수는 융합 후 결과 집합의 건수입니다(:ref:`rank-fusion-engine` 참조). +또한 패싯(레이블 등)의 건수는 메인 검색기의 검색 결과의 것이 그대로 사용됩니다. + +검색 엔진 측에서 융합하는 경우(:ref:`rank-fusion-engine` 참조), 총 히트 건수와 패싯 건수는 +키워드 검색과 시맨틱 검색 양쪽 히트의 합집합을 셉니다. 각 검색기가 샤드별로 제공하는 것은 최대 +``rank.fusion.pagination_depth`` 건이며, 시맨틱 검색기는 추가로 ``content_chunker.search.knn.k`` +건이 상한입니다. 그래서 같은 쿼리라도 ``rank.fusion.engine.enabled`` 를 전환하면 히트 건수도 +패싯 건수도 달라지며, 소규모 인덱스에서는 시맨틱 검색의 히트가 더해지는 검색 엔진 측 융합 쪽이 +더 커지기 쉽습니다. 사용 예 ======== diff --git a/ko/15.9/config/search-semantic.rst b/ko/15.9/config/search-semantic.rst index 895d96b1..3fe49a44 100644 --- a/ko/15.9/config/search-semantic.rst +++ b/ko/15.9/config/search-semantic.rst @@ -164,10 +164,13 @@ system.properties 설정 - ``768`` - 임베딩 벡터의 차원 수. 매핑 생성 시 이 값이 사용되므로 사용하는 임베딩 모델의 차원 수와 **반드시** 일치해야 합니다. 이 값에는 읽기 경로가 두 가지 있으며 동작이 다릅니다. 인덱스 - 매핑 생성 시에는 미설정·숫자가 아닌 값·0 이하·``16000``\ (k-NN 플러그인 자체의 상한) 초과 - 중 어느 경우든 경고와 함께 ``768`` 이 사용됩니다. 반면 임베딩 처리 실행 시에는 폴백이 + 매핑 생성 시에는 미설정이면 **경고 없이** ``768`` 이 사용되고, 빈 값·숫자가 아닌 값·0 + 이하·``16000``\ (k-NN 플러그인 자체의 상한) 초과이면 경고와 함께 ``768`` 이 사용됩니다. + 반면 임베딩 처리 실행 시에는 폴백이 없어, 미설정·숫자가 아닌 값·0 이하는 모두 오류가 됩니다. ``16000`` 을 초과하는 값은 실행 - 시에 거부되지 않으므로, 매핑만 ``768`` 로 생성되어 차원 불일치가 발생합니다 + 시에 거부되지 않으므로, 매핑만 ``768`` 로 생성되어 차원 불일치가 발생합니다. 매핑의 차원 + 수는 인덱스를 만든 뒤에는 변경할 수 없습니다. 미설정인 채로 만든 인덱스의 복구 방법은 + *주의 사항* 의 *차원 수를 설정하지 않고 인덱스를 만든 경우* 를 참조하세요 * - ``content_chunker.job.concurrency`` - ``2`` - 인덱서 작업의 병렬 워커 수 @@ -208,8 +211,10 @@ system.properties 설정 경고와 함께 ``cosinesimil`` 로 대체됩니다(매핑에 반영됨. 변경하려면 인덱스 재작성이 필요) * - ``content_chunker.search.knn.k`` - ``100`` - - ANN 쿼리당 검색할 이웃 수(|Fess| 측에서 융합하는 경우 딥 페이징 시 자동으로 확대됨. 검색 엔진 - 측에서 융합하는 경우에는 이 값이 그대로 사용됨) + - ANN 쿼리가 샤드별로 가져오는 이웃 수. |Fess| 측에서 융합하는 경우 실효값은 + ``rank.fusion.window_size`` 를 검색기 수로 나눈 값(기본값에서는 200 ÷ 2 = 100) 아래로 + 내려가지 않으므로, 그보다 작은 값은 효과가 없습니다. 검색 엔진 측에서 융합하는 경우에는 + 이 값이 그대로 사용됩니다 * - ``content_chunker.search.knn.param.ef_search`` - (미설정) - ANN 쿼리의 ``ef_search`` 파라미터 @@ -234,6 +239,16 @@ system.properties 설정 청크화되는 문서에만 영향을 줍니다. 이미 청크 배열로 저장된 문서는 다시 크롤링될 때까지 원래 경계를 유지합니다. +.. note:: + + ``content_chunker.length.chunk_size`` 는 문자 수로 지정하지만, 임베딩 모델이 한 번에 받아들일 + 수 있는 것은 토큰 수 상한까지입니다. |Fess| 는 임베딩 대상 텍스트를 잘라내지 않으므로 상한을 + 넘는 부분은 벡터에 반영되지 않을 수 있습니다. ``chunk_size`` 는 사용하는 모델의 입력 상한에 + 맞춰 선택하세요. 예를 들어 ``paraphrase-multilingual-MiniLM-L12-v2`` (최대 128 토큰)로 실측한 + 결과, 벡터에 반영된 범위는 영어로 약 440자, 일본어로 약 210자였습니다(텍스트에 따라 + 달라집니다). 이 모델에서는 기본값 ``chunk_size=800`` 인 청크의 뒷부분이 벡터에 반영되지 + 않습니다. + .. note:: HNSW의 ``m`` 및 ``ef_construction`` 파라미터는 ``doc.json`` 에 하드코딩되어 있으며 @@ -272,7 +287,8 @@ opensearch 프로바이더 연결 설정 - 연결 타임아웃(ms) * - ``content_chunker.embedding.opensearch.retry.max`` - ``3`` - - 일시적 오류(429, 5xx 등)에 대한 재시도 횟수 + - 일시적 오류(429, 5xx 등)에 대한 최대 시도 횟수(첫 번째 시도 포함). 재시도 횟수가 아닙니다. + ``3`` 이면 최대 3번 요청하고 그 사이의 대기는 2번입니다. ``1`` 이하이면 재시도하지 않습니다 * - ``content_chunker.embedding.opensearch.retry.base.delay.ms`` - ``2000`` - 재시도 기본 백오프 지연(ms) @@ -462,9 +478,14 @@ Docker 버전은 ``/opt/fess/system.properties``. 아래 항목은 모두 같은 ``embedding.name`` 에 지정한 프로바이더의 플러그인이 설치되어 있지 않은 경우에도 이 상태가 됩니다 * - ``skipped`` - - 처리가 스킵됨(예: ``max_chunks_per_document`` 초과) + - 처리가 스킵됨. 본문이 비어 있는(공백만 있는 경우 포함) 문서, 청크가 하나도 생성되지 않은 + 문서, ``max_chunks_per_document`` 를 초과한 문서가 해당됩니다. + ``content_chunker.chunker.name`` 에 존재하지 않는 이름을 지정한 경우에도 청커를 찾지 못해 + 청크가 생성되지 않으므로 모든 문서가 이 상태가 됩니다. 종료 상태이며, 작업을 다시 + 실행해도 재처리되지 않습니다 * - ``fail`` - - 처리 실패(로그를 확인하세요) + - 처리 실패(로그를 확인하세요). 종료 상태이며, 기본적으로 작업을 다시 실행해도 재처리되지 + 않습니다. 재처리하려면 ``content_chunker.job.retry_failed`` 를 ``true`` 로 설정합니다 검색 엔진에 직접 질의하여 상태 분포를 확인할 수 있습니다:: @@ -475,6 +496,29 @@ Docker 버전은 ``/opt/fess/system.properties``. 아래 항목은 모두 같은 ``missing`` 옵션에 의해 ``content_chunk_status`` 를 가지지 않는(즉 미처리) 문서는 ``pending`` 이라는 키의 버킷으로 집계됩니다. +청크 작업의 상황은 이 ``content_chunk_status`` 의 건수 분포로 판단하세요. 작업을 실행할 때마다 +``pending`` 이 줄고 ``done`` (chunk-only 모드에서는 ``chunked``)이 늘어나면 순조로운 것입니다. +``fail`` 이 나타나면 |Fess| 로그에서 원인을 확인하세요. ``skipped`` 는 본문이 빈 문서 등에서는 +정상이지만, 거의 모든 문서가 ``skipped`` 라면 ``content_chunker.chunker.name`` 의 오류를 +의심하세요(청커를 찾지 못하면 ``Chunker not found`` 라는 WARN 로그가 출력됩니다). + +.. warning:: + + 설정을 고치는 것만으로는 ``skipped`` 와 ``fail`` 이 원래대로 돌아가지 않습니다. ``skipped`` + 문서는 작업을 다시 실행해도 선택되지 않고(재크롤링된 문서는 미처리로 돌아갑니다), ``fail`` + 문서는 ``content_chunker.job.retry_failed`` 를 ``true`` 로 한 경우에만 다시 처리 대상이 + 됩니다. 예를 들어 ``content_chunker.chunker.name`` 을 잘못 지정한 채 작업을 실행해 모든 + 문서가 ``skipped`` 가 되었다면, 이름을 고친 뒤 ``content_chunk_status`` 를 삭제하고 나서 + 작업을 다시 실행하세요(``skipped`` 문서는 ``content`` 가 다시 쓰이지 않았으므로 그대로 + 재처리할 수 있습니다):: + + curl -XPOST "http://localhost:9200/fess.search/_update_by_query" \ + -H "Content-Type: application/json" -d ' + { + "query": {"term": {"content_chunk_status": "skipped"}}, + "script": {"source": "ctx._source.remove(\"content_chunk_status\")"} + }' + 시맨틱 검색의 동작 방식 ========================== @@ -748,6 +792,42 @@ fess-webapp-semantic-search 플러그인을 사용하고 있었던 경우 3. 위의 *설정 절차* 에 있는 *3. 인덱스 재작성(기존 환경에서 활성화하는 경우)* 에 따라 인덱스를 재작성하고 인덱서 작업을 다시 실행합니다. +차원 수가 같은 다른 모델로 변경하는 경우 +------------------------------------------ + +``content_chunker.embedding.opensearch.model.id`` 등 임베딩 모델 설정을 차원 수가 같은 다른 +모델로 변경해도 |Fess| 는 오류도 경고도 없이 받아들입니다. 검사되는 것은 차원 수뿐이며, 벡터를 +만든 모델은 인덱스에 기록되지 않기 때문입니다. 이 상태에서는 저장된 벡터는 이전 모델로, 검색 +시의 쿼리 벡터는 새 모델로 만들어져 서로 다른 벡터 공간에 있게 되므로 검색 결과의 관련성이 +무너집니다. 또한 코사인 유사도 값의 분포는 모델마다 다르므로, 이전 모델에 맞춰 조정한 +``content_chunker.search.min_score`` 가 새 모델에서는 너무 엄격해 대부분의 결과가 잘려 나갈 수 +있습니다. + +모델을 전환할 때는 새 모델을 설정한 뒤, 위의 *임베딩 모델(차원) 변경* 의 순서 1과 같은 +``_update_by_query`` 로 ``content_chunk_vector`` 와 ``content_chunk_status`` 를 삭제하고, +인덱서 작업을 다시 실행하여 모든 문서의 벡터를 다시 생성하세요(차원 수가 같으므로 인덱스를 +다시 만들 필요는 없습니다). ``content_chunker.search.min_score`` 를 설정했다면 새 모델에서 +다시 검토하세요. + +차원 수를 설정하지 않고 인덱스를 만든 경우 +--------------------------------------------- + +``content_chunker.embedding.dimension`` 이 미설정인 채로 ``fess.search`` 인덱스를 만들면 +``content_chunk_vector`` 의 매핑은 경고 없이 ``768`` 차원이 되며, 이후에는 변경할 수 없습니다. +이 상태에서 인덱서 작업을 실행하면 임베딩 처리 시 차원 수를 읽을 수 없어 오류가 되므로 문서가 +``fail`` 이 됩니다. + +- 사용하는 모델의 차원 수가 ``768`` 이라면 ``content_chunker.embedding.dimension=768`` 을 + 설정합니다. 매핑과 일치하므로 인덱스를 다시 만들 필요는 없습니다. +- ``768`` 이 아니라면 올바른 차원 수를 설정합니다. 매핑(``768``)과 설정값이 어긋나 있는 동안 + 인덱서 작업은 ERROR 로그를 출력하고 실행을 건너뜁니다. 위의 *임베딩 모델(차원) 변경* 의 + 순서 3과 같은 방법으로 인덱스를 다시 만드세요. + +어느 경우든 이미 ``fail`` 이 된 문서는 자동으로 재처리되지 않습니다. 인덱스를 다시 만드는 +경우에는 *임베딩 모델(차원) 변경* 의 순서 1의 ``_update_by_query`` 가 +``content_chunk_status`` 도 삭제합니다. 다시 만들지 않는 경우에는 +``content_chunker.job.retry_failed`` 를 일시적으로 ``true`` 로 설정하고 작업을 다시 실행하세요. + 디스크 사용량 -------------- diff --git a/zh-cn/15.9/api/api-search.rst b/zh-cn/15.9/api/api-search.rst index 84b6fc72..7a49dbf4 100644 --- a/zh-cn/15.9/api/api-search.rst +++ b/zh-cn/15.9/api/api-search.rst @@ -30,7 +30,7 @@ HTTP 方法 GET .. list-table:: 请求参数 * - ``q`` - - 搜索词(URL 编码)。 + - 搜索词(URL 编码)。最大长度由 ``api.param.max.length``\ (默认值 1000)限制,超过时返回 ``invalid_request`` 错误(HTTP 400)。该限制与搜索引擎自身的限制无关。 * - ``start`` - 从 0 开始的起始位置(integer,\ ``>=0``\ ,默认值 ``0``\ )。 * - ``offset`` diff --git a/zh-cn/15.9/config/rank-fusion.rst b/zh-cn/15.9/config/rank-fusion.rst index 3c956377..d9d5d2d6 100644 --- a/zh-cn/15.9/config/rank-fusion.rst +++ b/zh-cn/15.9/config/rank-fusion.rst @@ -212,12 +212,16 @@ JVM 系统属性 - ``rank.fusion.timeout`` 不适用。查询的嵌入会在发送搜索请求之前同步计算,因此如果嵌入提供商 响应缓慢或无响应,搜索会一直等待,最长直到提供商自身的超时时间(例如 - ``content_chunker.embedding.ollama.timeout``\ )。 + ``content_chunker.embedding.ollama.timeout``\ )。如果提供商会重试,重试的次数也会累加进来。 + 例如,内置的 ``opensearch`` 提供商会将 ``content_chunker.embedding.opensearch.timeout``\ (默认 + ``60000`` 毫秒)的等待最多重复 ``content_chunker.embedding.opensearch.retry.max``\ (默认 ``3``\ ) + 次,因此在提供商无响应时,默认情况下搜索可能被延迟 180 秒,再加上重试之间的等待时间。 - ``rank.fusion.window_size`` 和 ``rank.fusion.threads`` 仅在由 |Fess| 执行融合时使用。 - 由搜索引擎融合的搜索最多只能翻页到 ``rank.fusion.pagination_depth`` 条结果,因为搜索引擎 只融合每个搜索器在每个分片上排名前 ``rank.fusion.pagination_depth`` 的结果。总页数、是否有 - 下一页以及页码都止于此,请求从其之后开始的页面时,会返回与其他搜索请求超过 - ``index.max_result_window`` 的页面时相同的错误。即使在此范围内,从最后一条融合结果之后开始的 + 下一页以及页码都止于此,请求起始位置(``start``\ )大于等于 ``rank.fusion.pagination_depth`` 的 + 页面时,会返回与其他搜索请求超过 ``index.max_result_window`` 的页面时相同的错误(在 v2 搜索 API + 中为 HTTP 400 的 ``invalid_request``\ )。即使在此范围内,从最后一条融合结果之后开始的 页面(例如过时的链接)也会返回空页面。不由搜索引擎融合的搜索仍与以前一样,可以翻页到 ``index.max_result_window``\ 。 - 总命中数量低于 ``rank.fusion.pagination_depth`` 时是精确的。达到或超过该值时,搜索引擎统计的 @@ -292,7 +296,13 @@ Rank Fusion 在结合关键词搜索与语义搜索的 因此,即使是相同的查询,启用与不启用混合搜索时的命中数量也可能不同。 另外,当主搜索器的总命中数量以概算值(下限值)返回时,不会进行此修正。 -由搜索引擎执行融合时,总命中数量为融合后结果集的数量(请参阅 :ref:`rank-fusion-engine`\ )。 +另外,分面(标签等)的数量会原样采用主搜索器的搜索结果。 + +由搜索引擎执行融合时(请参阅 :ref:`rank-fusion-engine`\ ),总命中数量和分面数量统计的是关键词搜索与 +语义搜索两者命中结果的并集。每个搜索器在每个分片上最多提供 ``rank.fusion.pagination_depth`` 条 +结果,语义搜索器还额外受 ``content_chunker.search.knn.k`` 的限制。因此,同一个查询在切换 +``rank.fusion.engine.enabled`` 后,命中数量和分面数量都会不同;在小规模索引中,由搜索引擎执行融合 +时因为加入了语义搜索的命中,数量往往更大。 使用示例 ======== diff --git a/zh-cn/15.9/config/search-semantic.rst b/zh-cn/15.9/config/search-semantic.rst index d9e708b4..40469c03 100644 --- a/zh-cn/15.9/config/search-semantic.rst +++ b/zh-cn/15.9/config/search-semantic.rst @@ -152,10 +152,13 @@ system.properties 配置 * - ``content_chunker.embedding.dimension`` - ``768`` - 嵌入向量的维度。创建映射时会使用该值,因此它\ **必须**\ 与您所用嵌入模型的维度一致。该值有 - 两条读取路径,行为并不相同。创建索引映射时,未设置、非数字、小于等于 0、以及超过 - ``16000``\ (k-NN 插件自身的上限)的情况,都会带警告回退为 ``768``\ 。而在执行嵌入处理时 + 两条读取路径,行为并不相同。创建索引映射时,未设置时会\ **不带任何警告**\ 地回退为 ``768``\ ; + 为空、非数字、小于等于 0、以及超过 ``16000``\ (k-NN 插件自身的上限)的情况,则会带警告回退为 + ``768``\ 。而在执行嵌入处理时 没有任何回退,未设置、非数字、小于等于 0 都会直接出错。由于超过 ``16000`` 的值在运行时并 - 不会被拒绝,届时只有映射会以 ``768`` 创建,从而导致维度不一致 + 不会被拒绝,届时只有映射会以 ``768`` 创建,从而导致维度不一致。映射的维度在索引创建之后无法 + 更改;对于在未设置该值的情况下创建的索引,恢复方法请参阅“注意事项”中的“在未设置维度的情况下 + 创建了索引” * - ``content_chunker.job.concurrency`` - ``2`` - 索引器任务的并行工作线程数 @@ -195,8 +198,9 @@ system.properties 配置 ``cosinesimil``\ (会反映到映射中;更改需要重新创建索引) * - ``content_chunker.search.knn.k`` - ``100`` - - 每次 ANN 查询检索的邻居数量(由 |Fess| 执行融合时,深分页会自动放大;由搜索引擎执行 - 融合时按原值使用) + - 每次 ANN 查询在每个分片上检索的邻居数量。由 |Fess| 执行融合时,有效值不会低于 + ``rank.fusion.window_size`` 除以搜索器数量(默认为 200 ÷ 2 = 100),因此更小的值不起作用。 + 由搜索引擎执行融合时按原值使用 * - ``content_chunker.search.knn.param.ef_search`` - (未设置) - ANN 查询的 ``ef_search`` 参数 @@ -220,6 +224,14 @@ system.properties 配置 可完全复现此前的固定长度行为。修改这些设置只影响之后切分的文档:已经以分块数组形式 保存的文档会保留原有边界,直到被重新爬取。 +.. note:: + + ``content_chunker.length.chunk_size`` 以字符数指定,但嵌入模型一次只能接收不超过其 token 上限的 + 文本。|Fess| 不会截断送去嵌入的文本,因此超出上限的部分可能不会反映到向量中。请根据所用模型的 + 输入上限来选择 ``chunk_size``\ 。例如,使用 ``paraphrase-multilingual-MiniLM-L12-v2``\ (最多 + 128 个 token)实测,反映到向量中的范围在英文中约为 440 个字符,在日文中约为 210 个字符(因文本 + 而异)。对于该模型,默认值 ``chunk_size=800`` 的分块的后面部分不会反映到向量中。 + .. note:: HNSW 的 ``m`` 和 ``ef_construction`` 参数被硬编码在 ``doc.json`` 中(``m=16`` / @@ -257,7 +269,8 @@ opensearch 提供商的连接配置 - 连接超时(毫秒) * - ``content_chunker.embedding.opensearch.retry.max`` - ``3`` - - 针对瞬时错误(429、5xx 等)的重试次数 + - 针对瞬时错误(429、5xx 等)的最大尝试次数(包含第一次)。它不是重试次数:\ ``3`` 表示总共最多 + 发出三次请求,中间等待两次。小于等于 ``1`` 表示不重试 * - ``content_chunker.embedding.opensearch.retry.base.delay.ms`` - ``2000`` - 重试的基础退避延迟(毫秒) @@ -436,9 +449,13 @@ Docker 为 ``/opt/fess/system.properties``\ 。以下各项均写入同一个文 - 仅完成分块(仅分块模式)。除了 ``embedding.name=none`` 的情况之外,当 ``embedding.name`` 所指定的提供商对应的插件未安装时,也会进入此状态 * - ``skipped`` - - 处理被跳过(例如超过了 ``max_chunks_per_document``) + - 处理被跳过。包括正文为空(含仅有空白字符)的文档、没有生成任何分块的文档,以及超过 + ``max_chunks_per_document`` 的文档。如果 ``content_chunker.chunker.name`` 指定了不存在的 + 分块器,则找不到分块器、不会生成分块,所有文档都会进入此状态。这是终止状态:重新运行任务 + 不会再次处理该文档 * - ``fail`` - - 处理失败(请检查日志) + - 处理失败(请检查日志)。这是终止状态:默认情况下,重新运行任务不会再次处理该文档。 + 将 ``content_chunker.job.retry_failed`` 设为 ``true`` 才会再次处理 您可以直接查询搜索引擎来查看状态分布:: @@ -449,6 +466,28 @@ Docker 为 ``/opt/fess/system.properties``\ 。以下各项均写入同一个文 借助 ``missing`` 选项,不带 ``content_chunk_status``\ (即尚未处理)的文档会被聚合到键名为 ``pending`` 的分桶中。 +请根据 ``content_chunk_status`` 的这一数量分布来判断分块任务的状况。如果每次运行任务时 +``pending`` 都在减少、``done``\ (仅分块模式下为 ``chunked``\ )都在增加,说明进展顺利。 +如果出现 ``fail``\ ,请在 |Fess| 日志中确认原因。对于正文为空的文档等,出现 ``skipped`` 是正常的, +但如果几乎所有文档都是 ``skipped``\ ,请怀疑 ``content_chunker.chunker.name`` 有误(找不到分块器时 +会输出 ``Chunker not found`` 的 WARN 日志)。 + +.. warning:: + + 仅仅修正配置并不会让 ``skipped`` 和 ``fail`` 恢复原状。重新运行任务时不会选中 ``skipped`` + 文档(被重新爬取的文档会回到未处理状态),而 ``fail`` 文档只有在 + ``content_chunker.job.retry_failed`` 为 ``true`` 时才会再次成为处理对象。例如,如果 + ``content_chunker.chunker.name`` 有误的情况下运行了任务,导致所有文档都变成 ``skipped``\ , + 请在修正名称后,先按如下方式删除 ``content_chunk_status``\ ,再重新运行任务(``skipped`` + 文档的 ``content`` 没有被改写,因此可以直接重新处理):: + + curl -XPOST "http://localhost:9200/fess.search/_update_by_query" \ + -H "Content-Type: application/json" -d ' + { + "query": {"term": {"content_chunk_status": "skipped"}}, + "script": {"source": "ctx._source.remove(\"content_chunk_status\")"} + }' + 语义搜索的工作方式 ==================== @@ -700,6 +739,36 @@ Vector Indexer** 会在启动时自动注册,但由于默认处于禁用状态 3. 按照“配置步骤”中的“3. 重新创建索引(在现有部署上启用时)”重新创建索引,并重新运行索引器 任务。 +更换为维度相同的其他模型 +-------------------------- + +将 ``content_chunker.embedding.opensearch.model.id`` 等嵌入模型设置更改为维度相同的其他模型时, +|Fess| 不会报错也不会发出警告,直接接受。因为只检查维度,创建向量所用的模型并不会记录在索引中。 +此时已存储的向量由旧模型创建,而搜索时的查询向量由新模型创建,两者处于不同的向量空间, +搜索结果的相关性会崩溃。此外,余弦相似度的数值分布因模型而异,按旧模型调整过的 +``content_chunker.search.min_score`` 对新模型可能过于严格,导致大部分结果被截掉。 + +更换模型时,请先设置新模型,再用与上面“更改嵌入模型(维度)”步骤 1 相同的 ``_update_by_query`` +删除 ``content_chunk_vector`` 和 ``content_chunk_status``\ ,然后重新运行索引器任务,为所有文档 +重新生成向量(维度相同,因此无需重新创建索引)。如果设置了 ``content_chunker.search.min_score``\ , +请用新模型重新评估。 + +在未设置维度的情况下创建了索引 +-------------------------------- + +如果在 ``content_chunker.embedding.dimension`` 未设置的情况下创建 ``fess.search`` 索引, +``content_chunk_vector`` 的映射会不带任何警告地采用 ``768`` 维,并且之后无法更改。 +此时运行索引器任务,执行嵌入处理时无法读取维度而出错,文档会变为 ``fail``\ 。 + +- 如果所用模型的维度是 ``768``\ ,请设置 ``content_chunker.embedding.dimension=768``\ 。 + 它与映射一致,因此无需重新创建索引。 +- 否则,请设置正确的维度。在映射(``768``\ )与设置值不一致期间,索引器任务会输出 ERROR 日志并 + 跳过本次运行。请按上面“更改嵌入模型(维度)”步骤 3 的相同方法重新创建索引。 + +无论哪种情况,已经变为 ``fail`` 的文档都不会被自动重新处理。如果重新创建索引,上面“更改嵌入模型 +(维度)”步骤 1 的 ``_update_by_query`` 也会删除 ``content_chunk_status``\ 。如果不重新创建, +请临时将 ``content_chunker.job.retry_failed`` 设为 ``true`` 后重新运行任务。 + 磁盘使用量 ----------