# text מול keyword📖 שיעור

## מה זה?

בשיעור הקודם הגדרנו `name` כ-`text` ו-`category` כ-`keyword` — בלי להסביר למה. זו לא בחירה שרירותית: `text` מפרק את התוכן למילים בודדות (Analysis) כדי לאפשר חיפוש "חכם"; `keyword` שומר את הערך **כמו שהוא**, שלם ומדויק, לחיפוש-מדויק ומיון. בחירה הפוכה (`keyword` על תיאור מוצר, `text` על קטגוריה) שוברת את שני סוגי הפעולות.

## מילות מפתח שחשוב לזכור

• `text` — מנותח (Analyzed) למילים בודדות; מתאים לחיפוש חכם בתוכן חופשי (תיאורים, מאמרים)

• `keyword` — נשמר כמחרוזת שלמה ומדויקת, בלי ניתוח; מתאים לסינון מדויק, מיון, וקיבוץ (Aggregation)

• Analysis (ניתוח טקסט) — התהליך שהופך `text` למילים בודדות: פיצול למילים, המרה לאותיות קטנות, הסרת מילות-קישור

• Tokenization — שלב הפיצול עצמו בתהליך ה-Analysis, מטקסט שלם למילים (Tokens) נפרדות

```json
// name (text) — "Adidas running shoes" is broken into tokens: ["adidas", "running", "shoes"]
// searching on any one of the words separately will find the document

GET /products/_search
{
  "query": { "match": { "name": "running" } }
}
// finds "Adidas running shoes" — because "running" is one of the tokens
```

```json
// category (keyword) — "Footwear" is stored whole, not broken apart
// exact filtering — only an identical value matches

GET /products/_search
{
  "query": { "term": { "category": "Footwear" } }
}
// finds only documents where category equals exactly "Footwear"
// "term": { "category": "Foot" } will find nothing — no exact match
```

```json
// A field with both mappings together — best of both worlds
PUT /products
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "fields": { "keyword": { "type": "keyword" } }
      }
    }
  }
}
// name for smart search; name.keyword for exact filtering/sorting on the same field
```

## הסבר עיקרי

מתי `text` — כשרוצים "למצוא מסמכים שמכילים את המילה X" בלי קשר למיקום המדויק או לניסוח המלא — תיאורי מוצרים, תוכן מאמרים, כל טקסט חופשי שמישהו יחפש בתוכו חלקית. הניתוח (Analysis) הופך "נעלי ריצה אדידס" ל-3 טוקנים נפרדים, כך שחיפוש "ריצה" לבד עדיין מוצא את המסמך.

מתי `keyword` — כשרוצים **התאמה מדויקת** (קטגוריה, סטטוס, תג, מזהה), מיון לפי א'-ב', או קיבוץ (Aggregation, בשיעור הבא) — "כמה מוצרים בכל קטגוריה" דורש שהערך יישאר שלם ("הנעלה", לא "ה"+"נעלה" בנפרד), אחרת הקיבוץ יתפרק למילים בודדות חסרות משמעות.

השילוב (`fields`) הוא הפתרון המעשי הנפוץ ביותר — לפעמים רוצים **גם** חיפוש חכם וגם מיון/סינון מדויק על אותו שדה (למשל שם מוצר). ה-Mapping המשולב יוצר שני "צדדים" לאותו שדה: `name` (text, לחיפוש) ו-`name.keyword` (keyword, למיון/סינון מדויק) — שני שימושים, שדה מקור אחד.

## יתרונות

`text` מאפשר חיפוש חכם וגמיש בתוכן חופשי; `keyword` נותן דיוק מלא לסינון/מיון/קיבוץ; המיפוי המשולב (`fields`) נותן את שני היתרונות על אותו שדה בלי כפילות נתונים.

## חסרונות

בחירה שגויה (keyword על טקסט חופשי, או text על קטגוריה) שוברת שקטה את הפעולה המצופה, בלי שגיאה ברורה — רק תוצאות ריקות/לא-הגיוניות; המיפוי לא ניתן לשינוי בקלות אחרי יצירת ה-Index עם נתונים — דורש Reindex.

## נקודות חשובות

• `text` = מנותח למילים, לחיפוש חכם; `keyword` = שלם ומדויק, לסינון/מיון/קיבוץ

• חיפוש `term` על שדה `text` (מנותח) לרוב לא מוצא כלום — `term` דורש התאמה מדויקת לטוקן

• `fields` מאפשר מיפוי כפול (`name` + `name.keyword`) לאותו שדה מקור

• קיבוץ (Aggregation) כמעט תמיד דורש `keyword`, לא `text`

## טעויות נפוצות

• להגדיר קטגוריה/תג כ-`text` ולגלות שקיבוץ (Aggregation) מפרק אותם למילים בודדות חסרות הגיון

• להגדיר תיאור מוצר כ-`keyword` ולגלות שחיפוש חלקי לא מוצא כלום, כי נדרשת התאמה מדויקת לכל התיאור השלם

• להשתמש ב-`term` query על שדה `text` ולתהות למה תוצאה קיימת "לא נמצאת"

## סיכום

`text` מנתח תוכן למילים בודדות (Tokenization), מתאים לחיפוש חכם בטקסט חופשי. `keyword` שומר ערך שלם ומדויק, מתאים לסינון, מיון וקיבוץ. הבחירה הלא-נכונה שוברת בשקט את הפעולה המצופה — לא שגיאה גלויה, אלא תוצאות ריקות או לא-הגיוניות. מיפוי משולב (`fields`) מאפשר גם חיפוש חכם וגם דיוק על אותו שדה מקור, כשצריך את שניהם.

## דוקומנטציה רשמית

[Elasticsearch — Text vs keyword](https://www.elastic.co/guide/en/elasticsearch/reference/current/text.html)

---

## תרגילים

### תרגיל 1 — הדגמת ההבדל

**המשימה:** על Index עם `category` כ-`text`, נסו קיבוץ (Aggregation בסיסי) עליה, וראו שהתוצאה "מפורקת" למילים בודדות במקום קטגוריות שלמות.

**בדיקה:** הקיבוץ מציג טוקנים חסרי-הגיון (מילים בודדות) במקום שמות קטגוריה שלמים — הוכחה לבעיה.

### תרגיל 2 — מיפוי משולב

**המשימה:** הגדירו מחדש שדה `name` עם `fields.keyword`, והריצו חיפוש חכם על `name` וסינון מדויק על `name.keyword` על אותם נתונים.

**בדיקה:** `name` מוצא התאמות חלקיות (חיפוש חכם); `name.keyword` מוצא רק התאמה מדויקת לשלם — שני שימושים על אותו שדה מקור.

---

## פרויקט מסכם

**המשימה:** תקנו Mapping שגוי ב-Index "מאמרים" (מהפרויקט המסכם הקודם) שבו `tags` הוגדר בטעות כ-`text` במקום `keyword`.

**דרישות:**
1. זהו את הבעיה: הריצו קיבוץ על `tags` והראו תוצאה שגויה
2. תקנו את ה-Mapping (`tags` כ-`keyword`), עם Reindex אם נדרש
3. הריצו שוב את הקיבוץ ואמתו תוצאה נכונה — תגים שלמים, לא מפורקים למילים

**בדיקה:** אחרי התיקון, הקיבוץ על `tags` מציג ערכי תג שלמים והגיוניים, לא מילים בודדות מפורקות.

## מה בפרק הבא

בפרק הבא — **שאילתות: match, term, range, bool**: כלי החיפוש המרכזיים של Elasticsearch, כולל שילוב כמה תנאים יחד.
