Verbesserung der Suche vorhandener Dokumente
This commit is contained in:
109
lib/client.js
109
lib/client.js
@@ -183,16 +183,113 @@ export class PaperlessClient {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dokumente suchen. Vier Wege, in dieser Reihenfolge:
|
||||
*
|
||||
* 1. Archiv-Seriennummer, wenn die Eingabe nur aus Ziffern besteht.
|
||||
* Sie ist ein eigenes Feld - die Volltextsuche findet sie NICHT.
|
||||
*
|
||||
* 2. Die GLOBALE SUCHE von Paperless (/api/search/). Dieselbe
|
||||
* Schnittstelle, die die Suchleiste oben in der Weboberfläche
|
||||
* bedient. Sie verbindet Titelsuche und Volltext und liefert
|
||||
* damit die Ergebnisse, die man aus der Oberfläche kennt.
|
||||
*
|
||||
* 3. Teilzeichenkette in Titel und Inhalt. Greift, wenn die globale
|
||||
* Suche nichts liefert oder in der eingesetzten Version fehlt.
|
||||
*
|
||||
* 4. Volltextsuche über den Index, mit UND-Verknüpfung. Sie
|
||||
* beherrscht Wortstämme und findet auch Beugungsformen.
|
||||
*
|
||||
* Zwei Fallstricke, die hier berücksichtigt sind:
|
||||
*
|
||||
* * Bei der Volltextsuche darf KEIN ordering mitgegeben werden.
|
||||
* Paperless sortiert dort nach Relevanz; eine eigene
|
||||
* Sortierangabe führte dazu, dass die Suchanfrage verworfen wurde
|
||||
* und schlicht die zuletzt hinzugefügten Dokumente kamen.
|
||||
*
|
||||
* * Ohne UND-Verknüpfung sucht der Index mit ODER. "Anschreiben
|
||||
* Markus Straub" lieferte dann alles, was irgendeines der drei
|
||||
* Wörter enthält - der gesuchte Treffer ging darin unter.
|
||||
*/
|
||||
async search(query, limit = 50) {
|
||||
const q = String(query || "").trim();
|
||||
|
||||
if (!q) return this.#suchlauf({ ordering: "-added" }, limit);
|
||||
|
||||
// 1. Seriennummer
|
||||
if (/^\d+$/.test(q)) {
|
||||
const asn = await this.#suchlauf({ archive_serial_number: q }, limit);
|
||||
if (asn.length) return asn;
|
||||
}
|
||||
|
||||
// 2. Globale Suche wie in der Weboberfläche
|
||||
const global = await this.#globaleSuche(q, limit);
|
||||
if (global.length) return global;
|
||||
|
||||
// 3. Titel und Inhalt
|
||||
const text = await this.#suchlauf(
|
||||
{ title_content: q, ordering: "-created" }, limit);
|
||||
if (text.length) return text;
|
||||
|
||||
// 4. Volltext mit UND, ohne ordering.
|
||||
//
|
||||
// Nach dem Ersetzen der Sonderzeichen ERNEUT zerlegen: Aus
|
||||
// "Müller-Lüdenscheidt" würde sonst ein Wort mit Leerzeichen, und
|
||||
// die UND-Verknüpfung wäre wieder aufgehoben.
|
||||
const worte = q.replace(/[+\-&|!(){}[\]^"~*?:\\/]/g, " ")
|
||||
.split(/\s+/).filter(Boolean);
|
||||
if (!worte.length) return [];
|
||||
return this.#suchlauf({ query: worte.join(" AND ") }, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Schnittstelle hinter der Suchleiste der Weboberfläche.
|
||||
*
|
||||
* Sie gibt es erst ab neueren Paperless-Ständen, und die Form der
|
||||
* Antwort ist nicht überall gleich - mal ein Feld "documents", mal
|
||||
* "results". Deshalb wird beides angenommen und bei jedem Fehler
|
||||
* stillschweigend auf den nächsten Weg ausgewichen.
|
||||
*/
|
||||
async #globaleSuche(q, limit) {
|
||||
let antwort;
|
||||
try {
|
||||
const params = new URLSearchParams({ query: q,
|
||||
page_size: String(limit) });
|
||||
antwort = await this.#json(`search/?${params}`);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
if (!antwort) return [];
|
||||
|
||||
for (const schluessel of ["documents", "results"]) {
|
||||
const rows = antwort[schluessel];
|
||||
if (Array.isArray(rows) && rows.length) {
|
||||
// Die globale Suche liefert je nach Version verschiedene
|
||||
// Objektarten. Nur echte Dokumente durchlassen.
|
||||
return rows
|
||||
.filter((r) => r && typeof r === "object"
|
||||
&& r.id !== undefined && r.title !== undefined)
|
||||
.slice(0, limit);
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
async #suchlauf(zusatz, limit) {
|
||||
const params = new URLSearchParams({
|
||||
page_size: String(limit),
|
||||
ordering: "-added",
|
||||
fields: "id,title,created,added,archive_serial_number,mime_type," +
|
||||
"original_file_name"
|
||||
// Ohne diese Einschränkung liefert Paperless je Treffer auch den
|
||||
// vollständigen Inhalt - bei fünfzig Treffern mehrere Megabyte.
|
||||
fields: "id,title,created,added,archive_serial_number,mime_type,"
|
||||
+ "original_file_name"
|
||||
});
|
||||
if (query) params.set("query", query);
|
||||
const data = await this.#json(`documents/?${params}`);
|
||||
return data?.results || [];
|
||||
for (const [k, v] of Object.entries(zusatz)) params.set(k, String(v));
|
||||
try {
|
||||
const data = await this.#json(`documents/?${params}`);
|
||||
return data?.results || [];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
document(id) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"manifest_version": 3,
|
||||
"name": "__MSG_extName__",
|
||||
"description": "__MSG_extDescription__",
|
||||
"version": "1.14.3",
|
||||
"version": "1.16.0",
|
||||
"author": "Marco Morath",
|
||||
"homepage_url": "https://gitea.cloud.mmorath.de/marco.morath/thunderbird-paperless-connector",
|
||||
"default_locale": "de",
|
||||
|
||||
Reference in New Issue
Block a user