File size: 3,995 Bytes
abe028d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// OpenSearch Index Mapping for Vendor Search
// Supports faceted search: category, district, price range, rating, and full-text

PUT /vendors
{
  "settings": {
    "number_of_shards": 2,
    "number_of_replicas": 1,
    "analysis": {
      "analyzer": {
        "wedding_search": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["lowercase", "asciifolding", "stop", "snowball"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "id":              { "type": "keyword" },
      "businessName":    { "type": "text", "analyzer": "wedding_search", "fields": { "keyword": { "type": "keyword" } } },
      "categoryId":      { "type": "keyword" },
      "categoryName":    { "type": "keyword" },
      "district":        { "type": "keyword" },
      "description":     { "type": "text", "analyzer": "wedding_search" },
      "priceRange": {
        "type": "nested",
        "properties": {
          "min": { "type": "double" },
          "max": { "type": "double" }
        }
      },
      "rating":          { "type": "float" },
      "reviewCount":     { "type": "integer" },
      "isVerified":      { "type": "boolean" },
      "isPublished":     { "type": "boolean" },
      "features":        { "type": "keyword" },
      "packages": {
        "type": "nested",
        "properties": {
          "id":    { "type": "keyword" },
          "name":  { "type": "text" },
          "price": { "type": "double" }
        }
      },
      "availability": {
        "type": "nested",
        "properties": {
          "date": { "type": "date" },
          "type": { "type": "keyword" }
        }
      },
      "createdAt": { "type": "date" },
      "updatedAt": { "type": "date" }
    }
  }
}

// Indexer Worker (BullMQ job)
// On vendor create/update/publish, sync PostgreSQL -> OpenSearch:
//
// async function indexVendor(vendorId: string) {
//   const vendor = await db.vendorProfile.findUnique({
//     where: { id: vendorId },
//     include: { category: true, packages: true, availability: true }
//   })
//   if (!vendor) return
//   await esClient.index({
//     index: 'vendors',
//     id: vendor.id,
//     body: {
//       id: vendor.id,
//       businessName: vendor.businessName,
//       categoryId: vendor.categoryId,
//       categoryName: vendor.category.name,
//       district: vendor.district,
//       description: vendor.description,
//       priceRange: computePriceRange(vendor.packages),
//       rating: computeRating(vendor.id),
//       reviewCount: countReviews(vendor.id),
//       isVerified: vendor.isVerified,
//       isPublished: vendor.isPublished,
//       features: extractFeatures(vendor),
//       packages: vendor.packages.map(p => ({ id: p.id, name: p.name, price: Number(p.price) })),
//       availability: vendor.availability.map(a => ({ date: a.date, type: a.type })),
//       updatedAt: vendor.updatedAt,
//     }
//   })
// }
//
// // Faceted search example:
// POST /vendors/_search
// {
//   "query": {
//     "bool": {
//       "must": [
//         { "term": { "isPublished": true } }
//       ],
//       "filter": [
//         { "term": { "categoryName": "Photography" } },
//         { "term": { "district": "Colombo 3" } },
//         { "range": { "rating": { "gte": 4.5 } } }
//       ]
//     }
//   },
//   "aggs": {
//     "by_category":  { "terms": { "field": "categoryName" } },
//     "by_district":  { "terms": { "field": "district" } },
//     "price_ranges": {
//       "range": {
//         "field": "rating",  // placeholder - actual price range agg uses nested
//         "ranges": [
//           { "key": "Under 50K",  "to": 50000 },
//           { "key": "50K-100K",  "from": 50000, "to": 100000 },
//           { "key": "100K-250K", "from": 100000, "to": 250000 },
//           { "key": "250K-500K", "from": 250000, "to": 500000 },
//           { "key": "Over 500K",  "from": 500000 }
//         ]
//       }
//     }
//   },
//   "sort": [{ "rating": "desc" }]
// }