Elasticsearch: הגדרת חיפוש ליישומי אינטרנט

הקטלוג שלך גדל, וחיפוש לפי שם באמצעות PostgreSQL מתחיל לפגר — לקוחות עוזבים בלי לחכות לתוצאות. אנחנו מגדירים עבורך Elasticsearch: מנתחים את מבנה הנתונים, מתכננים אינדקסים ו-analyzers, ומסנכרנים עם PostgreSQL. אנחנו מספקים פתרון מלא — מבדיקת היתכנות ועד הטמעה ותמיכה שוטפת — כך שהחיפוש פועל במהירות ובאמינות.

פיתוח ותחזוקה של כל סוגי האתרים:

אתרי מידע או יישומי אינטרנט
אתרי תדמית, דפי נחיתה, אתרי חברה, קטלוגים מקוונים, חידונים, אתרי קידום, בלוגים, מקורות חדשות, פורטלי מידע, פורומים, אגרגטורים
אתרי מסחר אלקטרוני או יישומי אינטרנט
חנויות מקוונות, פורטלי B2B, שווקים, בורסות מקוונות, אתרי קאשבק, בורסות, פלטפורמות דרופשיפינג, מנתחי מוצרים
יישומי אינטרנט לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, פורטלים ארגוניים, מערכות ניהול ייצור, מנתחי מידע
אתרי שירות אלקטרוני או יישומי אינטרנט
פלטפורמות מודעות, בתי ספר מקוונים, בתי קולנוע מקוונים, בוני אתרים, פורטלים לשירותים אלקטרוניים, פלטפורמות אירוח וידאו, פורטלים נושאיים

אלה רק חלק מהסוגים הטכניים של אתרים שאנו עובדים איתם, ולכל אחד מהם יכולים להיות מאפיינים ופונקציונליות ספציפיים משלו, וכן ניתן להתאים אותם לצרכים ולמטרות הספציפיים של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
Elasticsearch: הגדרת חיפוש ליישומי אינטרנט
מורכב
~2-3 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1365
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113
  • פיתוח אתר עבור SBH Partners
    פיתוח אתר עבור SBH Partners
    1201
  • פיתוח אתר עבור Red Pear
    פיתוח אתר עבור Red Pear
    619

תארו לעצמכם שהחנות המקוונת שלכם גדלה ל-500,000 מוצרים, וחיפוש לפי שם באמצעות ILIKE % ב-PostgreSQL נתקע עם כל הקלדה. לקוחות עוזבים, ההמרה יורדת—כל שנייה של עיכוב מפחיתה אותה ב-7%. נתקלנו במצב הזה יותר מפעם אחת. בפרויקט אחד, חיפוש על פני מיליון מוצרים לקח 8 שניות; לאחר מעבר ל-Elasticsearch, זה היה 80 אלפיות השנייה. ההמרה גדלה ב-15%. במהלך השנים, הגדרנו את Elasticsearch ליותר מ-30 פרויקטים—מקטלוגים ועד שווקים. הניסיון שלנו מראה שהגדרת אינדקס ואנלייזר נכונה מפחיתה את זמן החיפוש פי 10.

למה Elasticsearch במקום חיפוש טקסט מלא ב-PostgreSQL?

PostgreSQL יכול לבצע חיפוש טקסט מלא באמצעות tsvector, אבל הוא מתקשה בעומסים כבדים, מורפולוגיה מורכבת ופאקטות. Elasticsearch עולה על PostgreSQL פי 10-20 במהירות בעומסים אמיתיים. השוו:

קריטריון PostgreSQL (ILIKE/tsvector) Elasticsearch
מהירות חיפוש עבור מיליון רשומות 200-500 אלפיות השנייה 10-50 אלפיות השנייה
מורפולוגיה רוסית בסיסית דרך מילונים גזירה, מילים נרדפות, אנלייזרים מותאמים אישית
סינון פאקטות מוגבל אגרגציות חזקות
השלמה אוטומטית פריצות עם טריגרמים Edge n-gram, Suggester
חיפוש גיאוגרפי דרך PostGIS, איטי טבעי, מהיר

בנוסף, החיפוש המבוזר של Elasticsearch מתמודד עם מיליארדי מסמכים.

איך אנו מגדירים את Elasticsearch למשימה שלכם

אנחנו לא מגדירים Elasticsearch "מתוך הקופסה." אנו תמיד מנתחים את מבנה הנתונים שלכם ואת השאילתות האופייניות. הנה דוגמה אמיתית: עבור קטלוג אלקטרוניקה עם 200,000 פריטים, יצרנו אינדקס עם שני אנלייזרים: רוסית (גזירה + מילות עצירה) והשלמה אוטומטית (edge n-gram). ההתקנה ארכה 4 ימים. בפרויקט אחר, היינו צריכים char_filter מותאם אישית כדי לנקות שמות מוצרים מתווים מיוחדים.

התקנת Elasticsearch 8.x

# Добавить репозиторий
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" > /etc/apt/sources.list.d/elastic-8.x.list
apt update && apt install -y elasticsearch
# Сохранить пароль superuser из вывода установки
systemctl enable elasticsearch && systemctl start elasticsearch

תצורה מינימלית לפיתוח עם צומת יחיד:

# /etc/elasticsearch/elasticsearch.yml
cluster.name: myapp-search
node.name: node-1
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
network.host: 127.0.0.1
discovery.type: single-node
xpack.security.enabled: true
xpack.security.http.ssl.enabled: false # для dev; в prod — включить

אנו מקצים heap כך: לא יותר מ-50% זיכרון RAM, לא יותר מ-32 GB (בגלל OOPs דחוסים). 4 GB מספיקים להתחלה.

מיפוי אינדקס

המיפוי מגדיר את סכימת האינדקס. מיפוי שגוי לא ניתן לתיקון ללא בנייה מחדש של האינדקס. קראו עוד במיפוי Elasticsearch:

PUT /products
{
  "settings": {
    "number_of_shards": 2,
    "number_of_replicas": 1,
    "analysis": {
      "analyzer": {
        "russian_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["lowercase", "russian_stop", "russian_stemmer"]
        },
        "autocomplete_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["lowercase", "edge_ngram_filter"]
        },
        "autocomplete_search": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["lowercase"]
        }
      },
      "filter": {
        "russian_stop": {
          "type": "stop",
          "stopwords": "_russian_"
        },
        "russian_stemmer": {
          "type": "stemmer",
          "language": "russian"
        },
        "edge_ngram_filter": {
          "type": "edge_ngram",
          "min_gram": 2,
          "max_gram": 20
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "name": {
        "type": "text",
        "analyzer": "russian_analyzer",
        "fields": {
          "autocomplete": {
            "type": "text",
            "analyzer": "autocomplete_analyzer",
            "search_analyzer": "autocomplete_search"
          },
          "keyword": {
            "type": "keyword"
          }
        }
      },
      "description": {
        "type": "text",
        "analyzer": "russian_analyzer"
      },
      "category": {
        "type": "keyword"
      },
      "brand": {
        "type": "keyword"
      },
      "price": {
        "type": "scaled_float",
        "scaling_factor": 100
      },
      "in_stock": {
        "type": "boolean"
      },
      "attributes": {
        "type": "object",
        "dynamic": true
      },
      "location": {
        "type": "geo_point"
      },
      "created_at": {
        "type": "date"
      }
    }
  }
}

שאילתת חיפוש עם פאקטות

POST /products/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "multi_match": {
            "query": "беспроводные наушники",
            "fields": ["name^3", "description", "name.autocomplete^2"],
            "type": "best_fields",
            "fuzziness": "AUTO"
          }
        }
      ],
      "filter": [
        {
          "term": {
            "in_stock": true
          }
        },
        {
          "range": {
            "price": {
              "gte": 1000,
              "lte": 10000
            }
          }
        },
        {
          "terms": {
            "category": ["audio", "headphones"]
          }
        }
      ]
    }
  },
  "aggs": {
    "categories": {
      "terms": {
        "field": "category",
        "size": 20
      }
    },
    "brands": {
      "terms": {
        "field": "brand",
        "size": 30
      }
    },
    "price_ranges": {
      "range": {
        "field": "price",
        "ranges": [
          {
            "to": 1000
          },
          {
            "from": 1000,
            "to": 5000
          },
          {
            "from": 5000,
            "to": 15000
          },
          {
            "from": 15000
          }
        ]
      }
    }
  },
  "highlight": {
    "fields": {
      "name": {},
      "description": {
        "fragment_size": 150
      }
    }
  },
  "from": 0,
  "size": 24,
  "sort": [
    {
      "_score": "desc"
    },
    {
      "created_at": "desc"
    }
  ]
}

איך להגדיר השלמה אוטומטית?

ההשלמה האוטומטית מיושמת באמצעות אנלייזר edge n-gram, כפי שמוצג במיפוי. Edge n-gram יוצר טוקנים מ-2 עד 20 תווים. משתמשים מקבלים הצעות לאחר הזנת 2-3 תווים—משפר את חוויית המשתמש. השדה # Добавить репозиторий wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" > /etc/apt/sources.list.d/elastic-8.x.list apt update && apt install -y elasticsearch # Сохранить пароль superuser из вывода установки systemctl enable elasticsearch && systemctl start elasticsearch ממפה את תחילת כל מילה. בשאילתות חיפוש, השתמשו ב-# /etc/elasticsearch/elasticsearch.yml cluster.name: myapp-search node.name: node-1 path.data: /var/lib/elasticsearch path.logs: /var/log/elasticsearch network.host: 127.0.0.1 discovery.type: single-node xpack.security.enabled: true xpack.security.http.ssl.enabled: false # для dev; в prod — включить או PUT /products { "settings": { "number_of_shards": 2, "number_of_replicas": 1, "analysis": { "analyzer": { "russian_analyzer": { "type": "custom", "tokenizer": "standard", "filter": ["lowercase", "russian_stop", "russian_stemmer"] }, "autocomplete_analyzer": { "type": "custom", "tokenizer": "standard", "filter": ["lowercase", "edge_ngram_filter"] }, "autocomplete_search": { "type": "custom", "tokenizer": "standard", "filter": ["lowercase"] } }, "filter": { "russian_stop": { "type": "stop", "stopwords": "_russian_" }, "russian_stemmer": { "type": "stemmer", "language": "russian" }, "edge_ngram_filter": { "type": "edge_ngram", "min_gram": 2, "max_gram": 20 } } } }, "mappings": { "properties": { "id": { "type": "keyword" }, "name": { "type": "text", "analyzer": "russian_analyzer", "fields": { "autocomplete": { "type": "text", "analyzer": "autocomplete_analyzer", "search_analyzer": "autocomplete_search" }, "keyword": { "type": "keyword" } } }, "description": { "type": "text", "analyzer": "russian_analyzer" }, "category": { "type": "keyword" }, "brand": { "type": "keyword" }, "price": { "type": "scaled_float", "scaling_factor": 100 }, "in_stock": { "type": "boolean" }, "attributes": { "type": "object", "dynamic": true }, "location": { "type": "geo_point" }, "created_at": { "type": "date" } } } } בשדה זה.

לוחות זמנים משוערים

לוחות הזמנים תלויים במורכבות. הגדרה בסיסית עם אינדקס אחד ואינטגרציה אורכת 3-5 ימים. אם אתם צריכים השלמה אוטומטית, פאקטות וסנכרון PostgreSQL, הוסיפו עוד 3-5 ימים. קלאסטר עם 3 צמתים וניטור אורך 1-2 שבועות. העלויות מחושבות באופן אישי. להלן לוח זמנים משוער לפי שלב:

שלב משך
ניתוח ועיצוב 1-2 ימים
התקנה והגדרת אינדקס 1-2 ימים
אינטגרציה עם היישום 2-3 ימים
בדיקות ואופטימיזציה 1-2 ימים
פריסה וניטור יום אחד

סנכרון נתונים מ-PostgreSQL

לסנכרון, אנו משתמשים ברפליקציה לוגית דרך Debezium + Kafka בתרחישי ייצור. להתחלה, בנייה מחדש תקופתית באמצעות cron מספיקה. להלן דוגמה ב-TypeScript:

// sync/product-indexer.ts
import { Client } from '@elastic/elasticsearch'
import { Pool } from 'pg'

const es = new Client({
  node: 'http://localhost:9200',
  auth: {
    username: 'elastic',
    password: process.env.ES_PASSWORD!
  }
})

const pg = new Pool({
  connectionString: process.env.DATABASE_URL
})

export async function indexProduct(id: string) {
  const { rows } = await pg.query(
    `
    SELECT p.*, c.name AS category_name,
           json_agg(json_build_object('key', a.key, 'value', a.value)) AS attributes
    FROM products p
    LEFT JOIN categories c ON c.id = p.category_id
    LEFT JOIN product_attributes a ON a.product_id = p.id
    WHERE p.id = $1
    GROUP BY p.id, c.name
    `,
    [id]
  )

  if (!rows.length) {
    await es.delete({ index: 'products', id })
    return
  }

  const p = rows[0]
  await es.index({
    index: 'products',
    id: p.id,
    document: {
      id: p.id,
      name: p.name,
      description: p.description,
      category: p.category_name,
      price: p.price,
      in_stock: p.stock_quantity > 0,
      attributes: Object.fromEntries(p.attributes?.map((a: any) => [a.key, a.value]) ?? []),
      created_at: p.created_at
    }
  })
}

export async function reindexAll() {
  const { rows } = await pg.query('SELECT id FROM products WHERE deleted_at IS NULL')
  const chunks = chunk(rows.map(r => r.id), 100)
  for (const ids of chunks) {
    await Promise.all(ids.map(indexProduct))
    console.log(`Indexed ${ids.length} products`)
  }
}

תוכנית הגדרה שלב אחר שלב

  1. ניתוח—לימוד מבנה הנתונים, שאילתות אופייניות, דרישות מהירות (1-2 ימים).
  2. עיצוב—פיתוח מיפוי, אנלייזרים, תוכנית סנכרון (1-2 ימים).
  3. יישום—התקנת Elasticsearch, הגדרת אינדקס, כתיבת אינטגרציה (3-5 ימים).
  4. בדיקות—בדיקת רלוונטיות חיפוש, פאקטות, מהירות (1-2 ימים).
  5. פריסה—פריסה לייצור, הגדרת ניטור (יום אחד).

מה כלול

לאחר סיום, אתם מקבלים:

  • קלאסטר Elasticsearch מוגדר (צומת יחיד או קלאסטר) עם גישה
  • אינדקסים עם אנלייזרים מותאמים אישית לשפה הרוסית
  • אינטגרציה עם היישום שלכם דרך REST API
  • סקריפטים לסנכרון נתונים (לדוגמה, מ-PostgreSQL)
  • תיעוד תפעולי
  • הדרכה לצוות שלכם

אנו נותנים אחריות ל-3 חודשים: אם החיפוש לא עובד כמצופה, אנו מתקנים זאת בחינם.

ניטור קלאסטר

אנו ממליצים לנטר את בריאות הקלאסטר דרך POST /products/_search { "query": { "bool": { "must": [ { "multi_match": { "query": "беспроводные наушники", "fields": ["name^3", "description", "name.autocomplete^2"], "type": "best_fields", "fuzziness": "AUTO" } } ], "filter": [ { "term": { "in_stock": true } }, { "range": { "price": { "gte": 1000, "lte": 10000 } } }, { "terms": { "category": ["audio", "headphones"] } } ] } }, "aggs": { "categories": { "terms": { "field": "category", "size": 20 } }, "brands": { "terms": { "field": "brand", "size": 30 } }, "price_ranges": { "range": { "field": "price", "ranges": [ { "to": 1000 }, { "from": 1000, "to": 5000 }, { "from": 5000, "to": 15000 }, { "from": 15000 } ] } } }, "highlight": { "fields": { "name": {}, "description": { "fragment_size": 150 } } }, "from": 0, "size": 24, "sort": [{ "_score": "desc" }, { "created_at": "desc" }] } ולהפעיל slowlog עבור שאילתות חיפוש. השתמשו ב-Elastic Metricbeat כדי לאסוף מדדים—זה עוזר לזהות הידרדרות בזמן.

טעויות נפוצות בהגדרה
  • מיפוי שגוי—מיפוי דינמי מוביל לסוגי שדות בלתי צפויים, ושובר פאקטות. תמיד הגדירו סכימה במפורש.
  • heap קטן מדי—זיכרון לא מספק גורם להשהיות GC תכופות וירידה בביצועים. הקצו לפחות 50% זיכרון RAM, אבל לא יותר מ-32 GB.
  • אין slowlog—בלעדיו, לא תראו שאילתות איטיות. הפעילו slowlog בתצורה: name.autocomplete.
  • התעלמות מרפליקות—לסבילות לתקלות, יש צורך לפחות ברפליקה אחת. הגדירו match_phrase_prefix.

התחילו את העבודה

אם החיפוש שלכם איטי או לא יכול להתמודד עם העומס, צרו קשר. אנו נעריך את המערכת שלכם ונציע פתרון. הזמינו הגדרת Elasticsearch סוהר—קבלו ייעוץ. אל תדחו: כל שנייה של עיכוב עולה לכם בלקוחות. בקשו ביקורת היום.