Indexer des Emoji
« 🍕 »
dans Elasticsearch pour trouver des pizzas !

@damienalexandre

Me

PHP, Elasticsearch, Symfony, Emoji

Pourquoi des emoji ?

  • Un texte seul porte difficilement un ton, une intonation, qu'un échange verbal permet
  • Avec l'explosion des conversations SMS et numériques, nous avons adopté des Emoticons :
:-)    :D    :-(     ^_^    ;-)    <3

En 1998, un opérateur Japonais introduit des icônes colorées dans les messages pour se démarquer de la concurrence.

176 pictogrammes de 12x12 pixels

NTT DoCoMo
Unicode

Unicode

  • Standard informatique du texte depuis 1991
  • Coordonné par le Consortium Unicode (organisation privée sans but lucratif)
  • Commence à s'intéresser aux Emoji en 2007

La naissance des Emoji

  • 855 emoji intégrés à Unicode 6.0 en 2010
    • Les pictogrammes Japonais
    • Quelques nouveaux
    • Certaines icônes déjà dans Unicode

🍢 🍤 🍥 🏯 👘 🎌 🗻 🎏

😑 😬 💩 🦄 🐙 🚙 🌦 🎸

□ Support aujourd'hui □

  • Apple iOS et macOS
  • Android
  • Windows 10
  • Linux 🐧 Ubuntu 18.04
  • caniemoji.com
  • Problèmes : sans couleurs ⛇, tofu □, invalide �...
  • Elasticsearch ?

Les code points

  • U+1F355 est 🍕
  • U+1F308 est 🌈
  • U+1F427 est 🐧

Les Emoji dans Unicode

Les emoji sont comme du texte. C'est votre système d'exploitation qui est capable de les afficher en image.

emoji display accross devices

Full emoji list.

Emoji fail cookies
Emoji fail burger order
Emoji fail hands

Peu importe ce qui est affiché, c'est le code point qui porte le sens.

Oui, vos utilisateurs vont saisir 🍕 dans votre moteur de recherche !

Github
Twitter
Yelp

Comment chercher comme Yelp


PUT meal/_doc/1
{
  "title": "pizza"
}

GET meal/_search
{
  "query": {
    "match": {
      "title": "🍕"
    }
  }
}

Aucun résultat

C'est standard

  • Unicode spécifie comment faire de la recherche (TR51)
  • Chaque emoji doit être indexé avec ses annotations, et cela dans toutes les langues cibles

Annotations CLDR de 🍕

  • En Anglais : cheese, pizza, slice
  • En Français : fromage, part, pizza



Nous devons indexer "pizza"
quand il y a un emoji 🍕

C'est le boulot des synonymes !

Elasticsearch

Dans Elasticsearch

  • Depuis 6.7 : Lucene 7.7.0 comprends les Emoji 🥰
  • Entre 6.4 et 6.7 : Plugin officiel analysis-icu
  • Avant 6.4 : 😵 Plugin maison 🔥 et plein de hack

Lucene 7.7 ❤️

Extrait des tests de Lucene :


/** simple emoji */
public void testEmoji() throws Exception {
    BaseTokenStreamTestCase.assertAnalyzesTo(
        a,
        "💩 💩💩",
        new String[] {"💩", "💩", "💩"},
        new String[] {"<EMOJI>", "<EMOJI>", "<EMOJI>"}
    );
}
Le commit qui a tout changé : "support Unicode UTS#51 v11.0 Emoji tokenization."

Emoji simple


GET _analyze
{
  "text": ["🍕"],
  "analyzer": "standard"
}

Token 🍕

Ajout des synonymes


GET _analyze
{
  "text": ["🍕"],
  "tokenizer": "standard",
  "filter": [
    {
      "type": "synonym",
      "synonyms": [
        "🍕 => 🍕, cheese, pizza, slice"
      ]
    }
  ]
}

Tokens 🍕 cheese pizza slice

Recherche fonctionnelle

Tokens 🍕 cheese pizza slice dans l'index

  • Recherche avec "🍕" : match ✅
  • Recherche avec "pizza" : match ✅

Liste de synonymes

  • Le CLDR fourni les annotations dans toutes les langues
  • Unicode Common Locale Data Repository
  • Je fournis juste les fichiers de synonymes déjà prêts :

https://github.com/jolicode/emoji-search/

    🐻 => 🐻, bear, bear face, face
    🐨 => 🐨, bear, koala
    🐼 => 🐼, face, panda, panda face
    🐾 => 🐾, feet, paw, paw prints, print
    🦃 => 🦃, bird, turkey
    🥵 => 🥵, feverish, heat stroke, hot, hot face, red-faced, sweating
    🥶 => 🥶, blue-faced, cold, cold face, freezing, frostbite, icicles
    🐣 => 🐣, baby, bird, chick, hatching, hatching chick
    🐤 => 🐤, baby, baby chick, bird, chick
    🐥 => 🐥, baby, bird, chick, front-facing baby chick
    🤞 => 🤞, cross, crossed fingers, finger, hand, luck
    🤟 => 🤟, hand, ILY, love-you gesture
    🌾 => 🌾, ear, grain, rice, sheaf of rice
    👱‍♀ => 👱‍♀, blond-haired woman, blonde, hair, woman, woman: blond hair
    🧓 => 🧓, adult, gender-neutral, old, older person, unspecified gender
    👴 => 👴, adult, man, old
    🧝‍♀ => 🧝‍♀, magical, woman elf
    🧞 => 🧞, djinn, genie
    ...
            

C'est un peu plus complexe dans la vraie vie

Composition

rainbow flag
  • Séquence ZWJ pour afficher un drapeau arc en ciel :
    1. 🏳 U+1F3F3
    2. ZWJ U+200D
    3. 🌈 U+1F308

ZWJ dans ES


GET _analyze
{
  "text": ["🏳‍🌈"],
  "tokenizer": "standard",
  "filter": [
    {
      "type": "synonym",
      "synonyms": [
        "🏳‍🌈 => 🏳‍🌈, pride, rainbow, rainbow flag"
      ]
    }
  ]
}

Tokens 🏳‍🌈 pride rainbow flag
La jointure est bien connue d'Elasticsearch

Drapeaux

  • 249 combinaisons basées sur ISO 3166-1 alpha-2
    • Regional indicator symbol :
      🇦 🇧 🇨 🇩 🇪 🇫 🇬 🇭 🇮 🇯 🇰 🇱 🇲 🇳 🇴 🇵 🇶 🇷 🇸 🇹 🇺 🇻 🇼 🇽 🇾 🇿
    • 🇨 U+1F1E8 + 🇦 U+1F1E6 = 🇨🇦
    • 🇨🇭 🇨🇳 🇩🇪 🇪🇸 🇫🇷 🇬🇧 🇮🇹 🇯🇵 🇰🇷 🇷🇺 🇺🇸...

Drapeaux

  • D'autres exemples :
    • 🇮🇨 IC Canary Islands
    • 🇽🇰 XK Kosovo
    • 🇺🇳 UN United Nations
    • 🇪🇺 EU European Union
    • 🇹🇼 TW Taiwan, caché en Chine

Drapeaux dans ES


GET _analyze
{
  "text": ["🇪🇺"],
  "tokenizer": "standard",
  "filter": [
    {
      "type": "synonym",
      "synonyms": [
        "🇪🇺 => 🇪🇺, flag: European Union"
      ]
    }
  ]
}

Tokens 🇪🇺 flag European Union
Combinaisons lues par Elasticsearch

Drapeau subdivision

  • ISO 3166-2 subdivisions administratives
    • 🏴󠁧󠁢󠁳󠁣󠁴󠁿 GB-SCT Écosse
    • 🏴󠁧󠁢󠁷󠁬󠁳󠁿 GB-WLS Wales
    • + de 3000 possibilitées
    • Seulement 4 supportées actuellement
    • On l'aura notre emoji BZH !

🏴󠁧󠁢󠁳󠁣󠁴󠁿 GB-SCT explosé

  • U+1F3F4 🏴
  • U+E0067 TAG g
  • U+E0062 TAG b
  • U+E0073 TAG s
  • U+E0063 TAG c
  • U+E0074 TAG t
  • U+E007F CANCEL TAG

Subdivisions dans ES


GET _analyze
{
  "text": ["🏴󠁧󠁢󠁳󠁣󠁴󠁿"],
  "tokenizer": "standard",
  "filter": [
    {
      "type": "synonym",
      "synonyms": [
        "🏴󠁧󠁢󠁳󠁣󠁴󠁿 => 🏴󠁧󠁢󠁳󠁣󠁴󠁿, flag, Scotland",
        "🏴󠁦󠁲󠁢󠁲󠁥󠁿 => 🏴󠁦󠁲󠁢󠁲󠁥󠁿, flag, Bretagne, BZH"
      ]
    }
  ]
}

Tokens 🏴󠁧󠁢󠁳󠁣󠁴󠁿 flag Scotland
Très bon support

Les modificateurs

  • Fitzpatrick
    • 🤘 U+1F918
    • 🤘🏽 U+1F918 + U+1F3FD

Fitzpatrick dans ES


GET _analyze
{
  "text": ["🤘🏽"],
  "tokenizer": "standard",
  "filter": [
    {
      "type": "synonym",
      "synonyms": [
        "🤘🏽 => 🤘🏽, horns, medium skin tone"
      ]
    }
  ]
}

Tokens 🤘🏽 horns medium skin tone
Supporté aussi mais synonyme à affiner

Sélecteur de variation

  • Variations, exemple avec HEAVY BLACK HEART
    • U+2764 en texte
    • ❤️ U+2764 + U+FE0F en Emoji
    • 🏳 U+FE0F ZWJ 🌈 !== 🏳 ZWJ 🌈

Variations ES


GET _analyze
{
  "text": ["🏳️‍🌈" , "❤️"],
  "tokenizer": "standard",
  "filter": [
    {
      "type": "synonym",
      "synonyms": [
        "🏳‍🌈 => 🏳‍🌈, pride, rainbow, rainbow flag",
        "❤ => ❤, heart, red heart"
      ]
    }
  ]
}

Tokens 🏳️‍🌈 ❤️
Nos synonymes ne matchent pas !

Variations ES

On supprime les variateurs AVANT le filtre de synonyme


{
  "type": "pattern_replace",
  "pattern": "\\uFE0E|\\uFE0F",
  "replace": ""
}

Tokens 🏳️‍🌈 ❤️ pride rainbow heart...

Les nouveaux emoji

  • Nouvelle version majeure d'Unicode tous les ans
  • Elasticsearch 7.10.2 = Lucene 8.7.0 = Unicode 11
  • Unicode 13 actuellement (Mars 2020)

Nouveaux emoji dans ES


GET _analyze
{
  "text": ["🤌🏽", "🥷🏿"]
}

Tokens 🤌 🏽 🥷 🏿 séparés !

Pinched Ninja

Mais globalement c'est très fonctionnel.

PUT /tweets
{
  "settings": {
    "analysis": {
      "filter": {
        "english_emoji": {
          "type": "synonym",
          "synonyms_path": "analysis/cldr-emoji-annotation-synonyms-en.txt"
        },
        "emoji_variation_selector_filter": {
          "type": "pattern_replace",
          "pattern": "\\uFE0E|\\uFE0F",
          "replace": ""
        }
      },
      "analyzer": {
        "english_with_emoji": {
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "emoji_variation_selector_filter",
            "english_emoji"
          ]
        }
      }
    }
  }
}
            
GET tweets/_analyze
{
  "analyzer": "english_with_emoji",
  "text": "🍕 🍍"
}

🍕 cheese pizza slice 🍍 fruit pineapple

Pizza

Pour résumer

  • Les emoji sont des lettres comme les autres 🔠
  • Leur recherche se base sur des synonymes 👥
  • Le CLDR produit ses annotations pour nous 📝
  • Un fichier de synonymes tout prêt disponible ✅
  • Il y a plein de combinaisons possibles ♾️
  • Supportez les emoji partout (sauf les mots de passe) 🔒

Merci pour votre attention 🤘

@damienalexandre
https://github.com/jolicode/emoji-search/

JoliCode

Développement Web
expertise
open-source