تجربة اليوزر · فصل ٤

مين يظهر الأول: BM25 والـ Boosting

Relevance · BM25 · field boosting · explain
🎯 الهدف: تخلي الموبايل يسبق الكفر من غير ما ترتّب بإيدك، وتفهم الـ score مش نسبة مئوية.

الاتنين فيهم الكلمة، وواحد بس هو المقصود

اليوزر كتب iPhone 15 Pro. عندك:

  • Apple iPhone 15 Pro — المنتج نفسه، والكلمات في الاسم.
  • Case compatible with iPhone 15 Pro — إكسسوار، والكلمات في وصف توافق.

الاتنين match. لو رجّعت الصفوف زي ما الداتابيز لقيتها، الكفر ممكن يبقى فوق. اليوزر هيحس إن البحث مكسور حتى لو “الكلمة موجودة”.

الترتيب بالنِيّة اسمه relevance ranking. Elasticsearch بيدي كل نتيجة _score. الأعلى يظهر الأول. الافتراضي من سنين هو خوارزم BM25.

BM25 بيبص على إيه؟

من غير ما نحفظ المعادلة، ثلاث حاجات بتحرّك الرقم:

  1. تكرار الكلمة في الحقل. بس مش خط مستقيم. تكرار زيادة بيفرق في الأول وبعدين التأثير بيقل، عشان حد ميحشي الوصف بكلمة iphone عشرين مرة ويطلع الأول.
  2. ندرة الكلمة. pro موجودة في منتجات كتير، فوزنها أقل من كلمة نادرة زي موديل قليل. كلمة الناس كلها كاتباها مش بتفرّق أوي.
  3. طول الحقل. نفس الكلمة في اسم قصير أقوى من وجودها وسط وصف من فقرتين. الاسم إشارة أوضح.

الـ _score رقم داخلي للمقارنة بين نتائج نفس السؤال. مش نسبة من ١٠٠، ومتعرضهوش لليوزر كـ “تطابق ٨٧٪”. سؤال تاني بأرقام تانية خالص.

الـ Boosting: الاسم أهم من الوصف

تقدر تقول للمحرك: خد تطابق name بوزن أعلى من description. ده boosting، وبيتعمل في الكويري مش في الـ mapping (الـ boost القديم على الحقل نفسه بقى قديم).

src/search-text.js
export function textQuery(q) {  return {    bool: {      should: [        { term: { sku: { value: q, boost: 20 } } },        {          multi_match: {            query: q,            fields: ["name^3", "description"],            type: "best_fields",          },        },      ],      minimum_should_match: 1,    },  };}

name^3 يعني مساهمة الاسم تتضرب في ٣ قبل ما تتقارن بالوصف. الرقم مش قانون سماوي. جرّب ٣ و ٥ على منتجات حقيقية: موبايل، كفر، شاحن متوافق، وإكسسوار اسمه فيه الكلمة بالصدفة. الـ SKU لو اتطابق بالظبط ياخد دفعة كبيرة عشان ميتوهش وسط نص شبيه.

شوف ليه النتيجة دي خدت الرقم ده

src/explain.js
import { es } from "./es.js";import { textQuery } from "./search-text.js";const explained = await es.explain({  index: "products",  id: "p-1001",  query: textQuery("iphone 15 pro"),});console.log(explained.explanation);

الـ API بيرجع شجرة: أنهي حقل ساهم، وأنهي كلمة كانت نادرة. استخدمه وأنت بتظبط الأوزان، مش في كل طلب بحث من الموقع. تقيل، وشكله مش لليوزر.

🧪 Lab

اعمل مستندين بنفس كلمات iPhone 15 Pro: واحد اسمه الموبايل، وواحد كفر والكلمات في الوصف بس. ابحث من غير name^3 وبعدين بيها. الموبايل المفروض يطلع فوق في الحالتين غالبًا بسبب طول الحقل، والـ boost بيزوّد الفرق. لو الكفر لسه فوق، الاسم عنده تحليل بيكسر الكلمات بشكل مختلف عن الوصف. ارجع لفصل التحليل قبل ما تزود الرقم.

✅ الخلاصة — Checklist

🧠 اختبر نفسك
١) ليه الكفر ممكن يعمل match ومع ذلك مينفعش يبقى الأول؟
لأن الكلمة موجودة، بس النِيّة كانت المنتج نفسه. الـ score بيفرق بين الاتنين.
٢) إيه فكرة boosting في المثال ده؟
تطابق الاسم يتوزن أعلى من تطابق الوصف.
٣) اليوزر رتّب بالسعر تصاعدي. مين بيرتّب؟
حقل السعر، مش BM25. الـ score مش بيتحكم في الصفحة دي.