Zum Inhalt springen

quelle: docs/METHODOLOGY.de.md

Methodik

Übersetzung des englischen Originals; die englische Fassung ist die Referenzversion.

Engine-Version 1.1.0. Dieses Dokument ist die einzige verbindliche Quelle dafür, wie jedes Signal und der Signalyze-Wert berechnet werden. Die Seite /methodology wird daraus erzeugt, und der Code in packages/signals (TypeScript) und apps/api/signalyze_api/engine (Python) setzt genau das um, was hier steht; beide Implementierungen werden an denselben Testfixtures gemessen.

Signalyze berechnet zehn deterministische Signale aus den Rezensionen, die auf einer Google-Maps-Unternehmensseite sichtbar sind. Jedes Signal ist eine Zahl zwischen 0 und 1, die ausdrückt, wie ungewöhnlich der gemessene Wert im Vergleich zu typischen bewerteten Orten ist; 0 bedeutet „unauffällig“, 1 bedeutet „so ungewöhnlich, wie wir es je sehen“. Der Signalyze-Wert (0-100) ist eine gewichtete Kombination der Signale, die berechnet werden konnten. Es ist kein Sprachmodell beteiligt, und über Absichten wird nichts abgeleitet: Jedes Signal ist eine Tatsache über die Verteilung öffentlicher Daten, die jeder von derselben Seite aus nachrechnen kann.

Dieser Wert ist eine statistische Zusammenfassung öffentlicher Bewertungsdaten; er ist keine Aussage über das Unternehmen oder einzelne Rezensenten.

Eingabe

Die Engine erhält pro Rezension: Sternebewertung (1-5), Kalendertag, Text, die öffentliche Rezensionsanzahl des Rezensenten (falls sichtbar), Fotoanzahl, Local-Guide-Stufe (falls sichtbar), Text der Inhaberantwort (falls vorhanden). Sie erhält nie Namen, Profil-Links oder Nutzer-IDs. Siehe Datenschutz.

Die Erweiterung lädt bis zu 200 Rezensionen (500 mit „Mehr laden“) in Googles Standardsortierung „Relevanteste“, sodass die Stichprobe der Teil der Rezensionsgeschichte ist, den Google zuerst anzeigt, und keine zufällige oder chronologische Stichprobe. Die Signale werden auf dieser Stichprobe berechnet, und das Seitenpanel zeigt immer, wie viele Rezensionen von der angezeigten Gesamtzahl analysiert wurden.

Vorverarbeitung

Von einer Messung zur „Ungewöhnlichkeit“

Jedes Signal erzeugt eine Rohmessung (meist einen Anteil zwischen 0 und 1) und bildet sie mit einer linearen Rampe zwischen zwei Kalibrierungspunkten auf die Ungewöhnlichkeit ab:

unusualness = clamp((value - low) / (high - low), 0, 1)

low ist das Niveau, ab dem das Signal zu zählen beginnt (typische Orte liegen darauf oder darunter), high das Niveau, ab dem es voll zählt. Die Kalibrierungspunkte liegen in packages/signals/data/thresholds.json und sind unten pro Signal aufgeführt. Es sind Schätzungen der Engine-Version 1.1.0, gewählt anhand der Form öffentlicher Google-Maps-Rezensionsdaten und synthetischer Datensätze; sie werden mit neuen Engine-Versionen überarbeitet, und jede Überarbeitung wird im Änderungsprotokoll festgehalten.

Die Signale

1. burst_ratio (Gewicht 0,16)

Misst: den Anteil der Rezensionen, die in das einzelne dichteste 14-Tage-Fenster fallen.

Wie: Rezensionstage sortieren; ein 14-Tage-Fenster verschieben und die höchste Anzahl nehmen; peakShare = peak / n. Ein gleichmäßiger Fluss über die Lebensdauer des Ortes würde expectedShare = 14 / lifespanDays Rezensionen in jedes Fenster legen, der Überschuss darüber ist also excess = (peakShare - expectedShare) / (1 - expectedShare). Passt die gesamte Historie in 14 Tage, gibt es nichts zu vergleichen, und der Überschuss ist 0.

Rampe: excess von 0,05 bis 0,65.

Warum es zählt: An etablierten Orten verteilt sich der Rezensionsfluss; ein großer Anteil aller Rezensionen innerhalb von zwei Wochen ist messbar und selten. Die Details enthalten die Daten des Fensters, damit es auf der Seite nachgeprüft werden kann.

2. rating_polarity (Gewicht 0,08)

Misst: den Anteil der 5-Sterne- plus 1-Stern-Bewertungen an allen Bewertungen.

Wie: share = (count5 + count1) / n.

Rampe: 0,82 bis 0,96. Google-Bewertungen sind stark zu 5 Sternen verschoben, ein hoher Polaritätsanteil ist also normal; nur Verteilungen, die 2-4 Sterne fast vollständig auslassen, werden gezählt.

Warum es zählt: Eine an beiden Extremen konzentrierte Verteilung unterscheidet sich von der gleichmäßigen, 5-lastigen Form der meisten Orte.

3. single_review_accounts (Gewicht 0,14)

Misst: den Anteil der Rezensenten, deren öffentliche Rezensionsanzahl 0 oder 1 ist.

Wie: unter den Rezensionen mit sichtbarer Anzahl share = count(reviewCount <= 1) / known. Benötigt mindestens 15 bekannte Anzahlen, sonst nicht verfügbar.

Rampe: 0,30 bis 0,75.

Warum es zählt: Die meisten Google-Rezensenten haben mehr als eine Rezension verfasst. Ein großer Anteil von Rezensenten, deren einzige Rezension diese ist, ist eine messbare Abweichung von dieser Basis.

4. no_photo_short_text (Gewicht 0,08)

Misst: den Anteil der Rezensionen ohne Foto und mit weniger als 40 Zeichen Text.

Wie: share = count(photoCount == 0 and textLength < 40) / n.

Rampe: 0,60 bis 0,95. Reine Sternebewertungen sind auf Google üblich, daher zählt nur ein sehr hoher Anteil.

Warum es zählt: Fotos und längere Texte kosten Mühe; ihr fast vollständiges Fehlen ist messbar.

5. text_similarity (Gewicht 0,16)

Misst: wie stark sich Rezensionstexte gegenseitig überlappen.

Wie: Für jede Rezension mit mindestens 20 Zeichen normalisiertem Text die Menge der Zeichen-3-Gramme bilden (Leerzeichen eingeschlossen). Für jedes Paar die Jaccard-Ähnlichkeit |A ∩ B| / |A ∪ B| berechnen. Den Mittelwert über alle Paare und den Anteil der Paare über 0,5 („nahezu identische Paare“) ausgeben. Benötigt mindestens 10 geeignete Texte.

Rampe: das Größere aus mittlerem Jaccard von 0,18 bis 0,45 und Anteil nahezu identischer Paare von 0,02 bis 0,15.

Warum es zählt: Unabhängig verfasste Texte über denselben Ort teilen einige Wörter, aber sehr wenige Fragmente auf 3-Gramm-Ebene. Hohe Überlappung ist unabhängig von der Sprache messbar.

6. template_phrases (Gewicht 0,08)

Misst: den Anteil der Rezensionen, deren Text überwiegend aus Standardphrasen besteht.

Wie: Pro Sprache wird ein Wörterbuch gängiger Standardphrasen („highly recommend“, „kesinlikle tavsiye ederim“, „sehr zu empfehlen“, „muy recomendable“, „je recommande“, „また来たい“, „强烈推荐“, …) mit Wortgrenzen auf den normalisierten Text angewendet; für Japanisch und Chinesisch, die ohne Leerzeichen geschrieben werden, werden Phrasen als einfache Teilzeichenketten gesucht. Eine Rezension ist phrasenbasiert, wenn die gefundenen Phrasen mindestens 50 % ihrer Zeichen abdecken. share = phraseBased / withText. Benötigt mindestens 10 Rezensionen mit Text. Texte, deren Sprache kein Wörterbuch hat, zählen in withText, sind aber nie phrasenbasiert. Die drei häufigsten Phrasen werden ausgegeben.

Rampe: 0,15 bis 0,50.

Warum es zählt: Standardphrasen kommen auch in alltäglichen Rezensionen vor; deshalb zählen nur Texte, die überwiegend daraus bestehen, und nur ihr Anteil an allen Texten.

7. rating_text_mismatch (Gewicht 0,08)

Misst: wie oft der Ton des Textes der Sternebewertung widerspricht.

Wie: Pro Sprache liefert ein kleines Lexikon positiver und negativer Wörter tone = (positive - negative) / (positive + negative) über die Tokens einer Rezension. Für Japanisch und Chinesisch werden die Lexikoneinträge als Teilzeichenketten des normalisierten Textes gesucht, längste Einträge zuerst; jeder Eintrag zählt einmal und wird entfernt, bevor kürzere Einträge geprüft werden, sodass eine verneinte Form wie 不好吃 in der Negativliste nicht zusätzlich als 好吃 zählt. Rezensionen ohne Lexikontreffer und Texte, deren Sprache kein Wörterbuch hat, werden nicht bewertet. Eine Abweichung ist eine Bewertung von 4 oder 5 mit Ton ≤ -0,5 oder eine Bewertung von 1 oder 2 mit Ton ≥ 0,5. share = mismatches / scored. Benötigt mindestens 10 bewertete Rezensionen.

Rampe: 0,10 bis 0,35. Das Lexikon erkennt weder Verneinung noch Ironie, daher wird ein Grundanteil an Abweichungen erwartet und nicht gezählt.

Warum es zählt: Text und Sterne stimmen normalerweise überein; systematische Abweichung ist messbar.

8. date_entropy (Gewicht 0,08)

Misst: wie gleichmäßig sich die Rezensionen über die Monate zwischen der ersten und der letzten Rezension verteilen.

Wie: Rezensionen pro Kalendermonat zählen; Shannon-Entropie H = -Σ p_i log2 p_i über die Monate, normalisiert mit log2(monthsInSpan). 1 bedeutet vollkommen gleichmäßig, 0 bedeutet alles in einem Monat. Benötigt eine Spanne von mindestens 3 Monaten. Der stärkste Monat und sein Anteil werden ausgegeben.

Rampe: 1 - normalisedEntropy von 0,25 bis 0,65.

Warum es zählt: Ergänzt burst_ratio auf Monatsebene; saisonale Orte haben eine etwas niedrigere Entropie, was die Rampe toleriert.

9. local_guide_ratio (Gewicht 0,06)

Misst: den Anteil der Rezensionen von Local Guides der Stufe 3 oder höher.

Wie: Wird nur berechnet, wenn die Seite für mindestens einen Rezensenten eine Stufe angezeigt hat; sonst nicht verfügbar, weil eine fehlende Stufe nicht von „kein Local Guide“ zu unterscheiden ist. share = count(level >= 3) / n. Die ungewöhnliche Richtung ist ein niedriger Anteil.

Rampe: Fehlbetrag 0.20 - share von 0 bis 0,20 (Anteil 0 → 1, Anteil ≥ 0,20 → 0).

Warum es zählt: Etablierte Local Guides gehören an den meisten Orten zum üblichen Rezensentenmix.

10. owner_response_pattern (Gewicht 0,08)

Misst: wie identisch die Antworten des Inhabers sind.

Wie: Unter den Rezensionen mit Inhaberantwort die normalisierten Antworten gruppieren; identicalShare = 1 - distinct / responded. Benötigt mindestens 5 Antworten. Die Antwortquote und der Anteil der größten Gruppe werden ausgegeben.

Rampe: 0,60 bis 0,95. Viele Inhaber verwenden einen Dankessatz mehrfach, daher zählt nur nahezu vollständige Wiederholung.

Warum es zählt: Ein kleiner, messbarer Aspekt der Seitenpflege; er ist niedrig gewichtet.

Der Signalyze-Wert

score = round( 100 × Σ (w_i × u_i) / Σ w_i )   over available signals i

Gewichte (packages/signals/src/weights.json, Version 1.1.0):

SignalGewicht
burst_ratio0.16
text_similarity0.16
single_review_accounts0.14
rating_polarity0.08
no_photo_short_text0.08
template_phrases0.08
rating_text_mismatch0.08
date_entropy0.08
owner_response_pattern0.08
local_guide_ratio0.06

Die Gewichte werden über die für den Ort verfügbaren Signale neu normalisiert, sodass ein Signal, das nicht berechnet werden konnte (zum Beispiel weil keine Local-Guide-Stufen angezeigt werden), den Wert in keine Richtung bewegt. Der Wert ist ein gewichteter Mittelwert, ein einzelnes Signal kann ihn also höchstens um seinen Gewichtsanteil anheben: Ein Ort mit einer extremen Häufung und sonst nichts Ungewöhnlichem landet bei etwa 25, nicht bei 90. Das ist beabsichtigt; das Seitenpanel zeigt jedes Signal einzeln, damit der Leser sieht, welches verantwortlich ist.

Kein Wert unter 15 Rezensionen. Mit weniger Rezensionen schwanken die obigen Anteile stark, daher zeigt die Erweiterung „nicht genug Daten“ und keine Zahl.

Wie die synthetischen Datensätze aussehen

Die Engine wird mit geseedeten synthetischen Datensätzen ausgeliefert, die in Tests und als Fixtures für den Abgleich der Implementierungen dienen (packages/signals/fixtures/). Ihre Werte bei Engine 1.1.0, zur Orientierung:

DatensatzBeschreibungWert
normalstetiger Fluss über drei Jahre, gemischte Bewertungen, natürliche Texte1-3
polarizedüberwiegend 5- und 1-Stern-Bewertungen7-12
burst60 % der Rezensionen in einem 14-Tage-Fenster, überwiegend Konten mit einer Rezension24
templateStandardphrasen-Texte, nahezu identische Texte, Konten mit einer Rezension, identische Inhaberantworten43-53
sparsenur Bewertungen, kein Text und keine Rezensentendaten21 (nur vier Signale verfügbar)
multilingualnatürliche und Standardphrasen-Texte in allen 18 abgedeckten Sprachen sowie Thai, Hindi und Griechisch4

Grenzen

Optionales Sprachmodell (standardmäßig aus)

Engine 1.1.0 enthält einen optionalen serverseitigen Schritt, den der Betreiber aktivieren kann: Wenn text_similarity bereits hoch ist, werden bis zu 30 Texte (ohne Rezensentendaten) an einen OpenAI-kompatiblen Endpunkt gesendet, der eine einzelne Zahl zurückgibt, eine Schätzung der „Schreibhomogenität“ von 0 bis 1, die in den Details von text_similarity als llmHomogeneity ausgegeben wird. Einzelne Rezensionen werden nie gekennzeichnet, und der Wert ändert sich in dieser Version nie dadurch. Der Schritt ist deaktiviert, solange nicht sowohl LLM_BASE_URL als auch LLM_API_KEY konfiguriert sind; die öffentliche Signalyze-API läuft derzeit mit deaktiviertem Schritt.