# PropTech listing search tier decision matrix (2026)

| Requirement | DynamoDB + GSI geo | OpenSearch `geo_point` + k-NN | Amazon Location + external index |
|-------------|------------------|------------------------------|----------------------------------|
| &lt; 500k active listings, simple bbox filter | **2** | 1 | 1 |
| Full-text + facets + geo polygon | 0 | **2** | 0 |
| Semantic "homes like this" search | 0 | **2** (k-NN ≤16k dims) | 0 |
| Autocomplete on address/street | 1 | **2** | **2** (Place Index) |
| Spring season 10× traffic spike | 1 | **2** with autoscaling | 1 |

## Opinionated default

**DynamoDB single-table canonical store first** — composite key `(marketId, listingId)`, GSI on `geoHash` + `status`. Add **OpenSearch** when you need polygon search, relevance ranking, or embedding similarity across **&gt;100k** searchable documents.

## Image pipeline tier

| Volume | Pattern |
|--------|---------|
| &lt; 5 TB images | S3 Standard → CloudFront; lifecycle to Intelligent-Tiering after 90 days |
| &gt; 5 TB, seasonal cold | Intelligent-Tiering from day 1; Rekognition batch on ingest queue |
| MLS burst (full sync) | SQS + Lambda resize → WebP variants; never serve raw MLS TIFF to mobile |

## When NOT to stand up OpenSearch on day one

- MVP with one MLS feed and map-only UX
- Team has no OpenSearch ops runbook (patch cadence, UltraWarm, FGAC)
- Search QPS &lt; 50 sustained — API Gateway + DynamoDB GSI is cheaper

## Rekognition scope honesty

- **Off-the-shelf labels** — pool, kitchen, curb appeal (marketing tags)
- **Custom Labels** — condition scoring (roof, foundation) only after **≥500** labeled images per class
