ספקים קוראים לאותם מאפיינים בשמות שונים: "Цвет", "Цвет изделия", "color", "Colour", "RAL". במסנן המוצרים קיים מאפיין יחיד "Color". יישור ידני של מאפיינים מעשרות ספקים למסנני מוצרים—מדובר במאות שעות עבודה שדורשות אוטומציה. אנו מפתחים מערכת יישור מאפיינים במפתח מלא: אתם מעלים רשימות מחירים, אנו מגדירים מילונים, אלגוריתמי נורמליזציה ואינטגרציה עם חיפוש פקטלי. לצוות שלנו ניסיון של 5+ שנים באוטומציה של קטלוגים במסחר אלקטרוני, והוא השלים למעלה מ-20 פרויקטים דומים. חיסכון בתקציב לכל ספק: מ-$270–390 בשנה (כ-$300 בקירוב). זמן העיבוד לכל ספק יורד מ-40 שעות ל-2–3 שעות—פי 10–20 מהר יותר. עם 20 ספקים, אתם חוסכים למעלה מ-700 שעות בשנה, שניתן להפנות לפיתוח הקטלוג. עלות ההטמעה האופיינית מתחילה מ-$2,500 לאינטגרציה של ספק יחיד, עם החזר השקעה תוך פחות מ-6 חודשים. המערכת האוטומטית שלנו יעילה פי 20 מהזנת נתונים ידנית, ומטפלת באלפי מאפיינים בדקה עם שגיאות כמעט אפסיות. אנו מבטיחים אינטגרציה חלקה עם קטלוג המוצרים שלכם. אנו משתמשים ב-PostgreSQL עם תוסף pg_trgm לחיפוש מטושטש ותורים לערכים לא מזוהים.
ארכיטקטורת המערכת ליישור מאפיינים
שלוש רמות הפשטה:
Характеристика поставщика → Атрибут сайта → Значение фильтра
"Цвет изделия: Красный" → color → "Красный"
"color: Red" → color → "Красный" (с нормализацией значения)
"RAL 3020" → color → "Красный" (через справочник RAL)טבלאות מיפוי—attribute_name_mapping (שם מאפיין) ו-attribute_value_mapping (ערך). שתיהן תומכות בעדיפות: קודם מיפוי לספק ספציפי, ולאחר מכן אוניברסלי. זה מאפשר להגדיר חריגים לספקים בודדים. הטבלה product_filter_values מאחסנת נתונים מנורמלים עם אינדקסים, מה שמבטיח סינון פקטלי מהיר. כאשר המיפוי משתנה, הנתונים מחושבים מחדש באמצעות פקודת artisan.
אלגוריתם המיפוי
המחלקה הראשית Характеристика поставщика → Атрибут сайта → Значение фильтра "Цвет изделия: Красный" → color → "Красный" "color: Red" → color → "Красный" (с нормализацией значения) "RAL 3020" → color → "Красный" (через справочник RAL) מבצעת התאמה אוטומטית של ערכי ספקים למאפייני האתר:
- קובעת את מפתח המאפיין הפנימי (
AttributeMapper,color) מתוך השם שסופק על ידי הספק. - בוחרת ערך מנורמל—או ממילון המיפוי או דרך מנרמל אוטומטי.
class AttributeMapper {
public function mapAttribute(
string $supplierName,
string $supplierValue,
?int $supplierId = null
): ?MappedAttribute {
// Шаг 1: найти маппинг имени атрибута
$siteAttribute = $this->resolveAttributeName($supplierName, $supplierId);
if (!$siteAttribute) {
$this->logUnknownAttribute($supplierName, $supplierId);
return null;
}
// Шаг 2: найти маппинг значения
$siteValue = $this->resolveAttributeValue($siteAttribute, $supplierValue, $supplierId);
if (!$siteValue) {
// Пробуем нормализовать без маппинга
$siteValue = $this->autoNormalizeValue($siteAttribute, $supplierValue);
}
return new MappedAttribute($siteAttribute, $siteValue);
}
private function resolveAttributeName(string $name, ?int $supplierId): ?string {
$normalized = mb_strtolower(trim($name));
// Сначала специфичный маппинг для поставщика
if ($supplierId) {
$mapping = AttributeNameMapping::where([
'supplier_id' => $supplierId,
'supplier_name' => $normalized,
])->value('site_attribute');
if ($mapping) return $mapping;
}
// Затем универсальный
return AttributeNameMapping::whereNull('supplier_id')
->where('supplier_name', $normalized)
->value('site_attribute');
}
} כיצד ערכים מנורמלים אוטומטית?
מאפיינים מספריים (משקל, מידות, מתח) מנורמלים ללא מילונים: "2,5 кг" → spec_weight_kg, "1000 г" → class AttributeMapper { public function mapAttribute( string $supplierName, string $supplierValue, ?int $supplierId = null ): ?MappedAttribute { // Шаг 1: найти маппинг имени атрибута $siteAttribute = $this->resolveAttributeName($supplierName, $supplierId); if (!$siteAttribute) { $this->logUnknownAttribute($supplierName, $supplierId); return null; } // Шаг 2: найти маппинг значения $siteValue = $this->resolveAttributeValue($siteAttribute, $supplierValue, $supplierId); if (!$siteValue) { // Пробуем нормализовать без маппинга $siteValue = $this->autoNormalizeValue($siteAttribute, $supplierValue); } return new MappedAttribute($siteAttribute, $siteValue); } private function resolveAttributeName(string $name, ?int $supplierId): ?string { $normalized = mb_strtolower(trim($name)); // Сначала специфичный маппинг для поставщика if ($supplierId) { $mapping = AttributeNameMapping::where([ 'supplier_id' => $supplierId, 'supplier_name' => $normalized, ])->value('site_attribute'); if ($mapping) return $mapping; } // Затем универсальный return AttributeNameMapping::whereNull('supplier_id') ->where('supplier_name', $normalized) ->value('site_attribute'); } } . ערכי מחרוזת בדרך כלל מומרים לאותיות קטנות או גדולות באות הראשונה (אם לא מדובר בשם מותג). עבור צבעים, נעשה שימוש בהתייחסות RAL—אנו משלבים אותה במהלך ההתקנה.
private function autoNormalizeValue(string $attribute, string $raw): string {
return match ($attribute) {
'spec_weight_kg' => $this->parseWeight($raw),
'spec_dimensions' => $this->parseDimensions($raw),
'spec_voltage' => $this->parseVoltage($raw),
default => $this->capitalizeFirst($raw),
};
}
private function parseWeight(string $raw): string {
// "2,5 кг" | "2500 г" | "2.5kg" → "2.5"
if (preg_match('/(\d+[.,]\d+|\d+)\s*г(?:рамм)?/iu', $raw, $m)) {
return (string) (((float) str_replace(',', '.', $m[1])) / 1000);
}
if (preg_match('/(\d+[.,]\d+|\d+)\s*кг/iu', $raw, $m)) {
return str_replace(',', '.', $m[1]);
}
return $raw;
} | ערך גולמי | מאפיין | תוצאה |
|---|---|---|
| 2,5 кг | spec_weight_kg | 2.5 |
| 2500 г | spec_weight_kg | 2.5 |
| Red | color | красный |
| RAL 3020 | color | Красный |
דוגמה למיפוי עבור ספק "ТехноКом":
- נתונים גולמיים: "Цвет: Red", "Вес: 2.5 kg"
- מיפוי: "Цвет" -> color, "Red" -> Красный; "Вес" -> spec_weight_kg, "2.5 kg" -> 2.5
- תוצאה: המוצר מופיע במסנן "Color: Красный" ו-"Weight: 2.5"
מדוע חיפוש מטושטש חשוב לערכים חדשים?
שימו לב: כאשר רשימת מחירים מכילה "Красн." אך המילון כולל רק "Красный", המערכת מציעה למפעיל ליצור מיפוי על בסיס דמיון מחרוזות. אנו משתמשים בפונקציה 2.5 מהמודול pg_trgm. בסף >0.6, מוצגות אפשרויות. המפעיל מאשר בלחיצה אחת—ובהיבוא הבא, הערך כבר ממופה אוטומטית. זה מבטל חיפוש ידני בקטלוג.
תוצרים מסחריים
- עיצוב מבני טבלאות מיפוי ונורמליזציה.
- פיתוח אלגוריתמים (מיפוי מילוני, נורמליזציה אוטומטית, חיפוש מטושטש).
- אינטגרציה עם חיפוש פקטלי: כתיבת ערכים ל-
1.0והגדרת אינדקסים. - ממשק ניהול לניהול מיפוי ותור של מאפיינים לא מזוהים.
- גישה לקוד המקור ותיעוד להרחבת מילונים ומנרמלים.
- הכשרת מפעילים ותמיכה שוטפת בחודש הראשון.
- ביצועים מובטחים ותאימות לקטלוג המוצרים שלכם.
לוחות זמנים להטמעה
| שלב | משך |
|---|---|
| מיפוי בסיסי של שמות מאפיינים + כתיבה למסננים | 3 ימים |
| נורמליזציה אוטומטית של ערכים מספריים | +יום אחד |
| הצעות מטושטשות + תור לא מזוהה + ממשק ניהול | +2–3 ימים |
| אינטגרציה מלאה עם חיפוש פקטלי וחישוב מחדש בעת שינוי מיפוי | +1–2 ימים |
לוח הזמנים הכולל נע בין 3 ל-9 ימים, תלוי במספר הספקים ובמורכבות נתוני הייחוס. המערכת שלנו עולה על שיטות ידניות בסדר גודל. בקשו הדגמה על הנתונים שלכם—ראו את החיסכון.
טעויות מיפוי אופייניות
- התעלמות מהקשר הספק. אם ספק אחד קורא ל-"длина" מידה ואחר מאפיין, מיפוי אוניברסלי שובר את הסינון. השתמשו תמיד ב-supplier_id.
- חוסר נורמליזציה של יחידות. ערבוב ק"ג וגרמים במסנן אחד הופך אותו לחסר תועלת. אנו מגדירים נורמליזציה אוטומטית למבחר שלכם.
- שכחת ערכים חדשים. ללא תור למאפיינים לא מזוהים, תאבדו מוצרים מהסינון. המערכת שלנו צוברת סטטיסטיקות ומדגישה החמצות תכופות.
- אין חישוב מחדש של מסננים בעת שינוי מיפוי. אם
private function autoNormalizeValue(string $attribute, string $raw): string { return match ($attribute) { 'spec_weight_kg' => $this->parseWeight($raw), 'spec_dimensions' => $this->parseDimensions($raw), 'spec_voltage' => $this->parseVoltage($raw), default => $this->capitalizeFirst($raw), }; } private function parseWeight(string $raw): string { // "2,5 кг" | "2500 г" | "2.5kg" → "2.5" if (preg_match('/(\d+[.,]\d+|\d+)\s*г(?:рамм)?/iu', $raw, $m)) { return (string) (((float) str_replace(',', '.', $m[1])) / 1000); } if (preg_match('/(\d+[.,]\d+|\d+)\s*кг/iu', $raw, $m)) { return str_replace(',', '.', $m[1]); } return $raw; }לא מעודכן, החיפוש מחזיר תוצאות שגויות. אנו מבצעים אוטומציה של חישוב מחדש בכל שינוי.







