Sentiment per aspect, not just per review. Knowing a review mentions
cleanliness is close to useless; knowing it complains about cleanliness while
praising the location is the product:
"sentimentAspects": {
"location": { "score": 4.38, "clauses": 1 },
"communication": { "score": 4.38, "clauses": 1 },
"cleanliness": { "score": -4.20, "clauses": 1 },
"comfort": { "score": -4.20, "clauses": 1 }
}
Six of the eight aspects are exactly the categories Airbnb itself rates
(cleanliness, accuracy, check-in, communication, location, value), so a text
score sits on the same axis as the published number. comfort and amenities
are kept because guests write about them constantly.
ratingVsText in the per-listing rollup — text sentiment minus the star
rating, both on −1..1. Airbnb ratings are compressed (most listings sit
between 4.7 and 5.0) and average the listing's entire history, while text is
current. A clearly negative gap means recent guests are writing complaints the
headline rating has not caught up with. Five stars on "the place was filthy,
the smell was disgusting and the host was rude" now reports -1.92.
Negation and intensifiers in all six languages. "No estaba limpio" is not
a compliment. Flips are damped rather than mirrored, so "not great" lands
milder than "terrible".
Contrast handling. "We had high hopes but it was terrible" used to net
to zero, because AFINN scores hopes (+2) and reach (+1) against terrible
(−3). What follows the contrast marker now carries the verdict. Applies to the
review-level score only — aspect scores stay unweighted, since "the location
is great but it was filthy" is equally true about both.
sentimentSupported and sentimentLanguage. Reviews in a language
outside the supported six return null rather than neutral, and the run log
reports what share of the set was actually scored. Conflating "unknown" with
"neutral" silently biases every aggregate toward the middle.
LISTING_SUMMARY in the key-value store — one row per listing with the
aspect breakdown, so listings can be compared without reading the review-grain
dataset.
Recency split. aspectsRecent (last 24 months by default) and
aspectTrend alongside the lifetime aspects. A lifetime mean has the exact
flaw this Actor exists to expose in the star rating: a problem fixed two years
ago still drags the number down. Measured on a real listing
(496506725996433560, 66 reviews), amenities read −0.92 across 2022-23
and +4.01 across 2024-26 — the host had fixed the internet and the
kitchen. The lifetime figure said +1.20 and pointed at nothing useful.
A trend is only emitted where both windows hold at least three reviews.
Reviews whose date cannot be parsed are counted in undatedReviews rather
than quietly dropped.
76 assertions covering both original bugs, negation and contrast in all six
languages, negation scoping, aspect attribution, the recency split, and the
aggregate edge cases.