Analyzers in Elastic Search

Stel je voor je wilt in je ES index specifiek kunnen zoeken op domeinnamen. Nou standaard werkt dat dus niet.

Analyzer

Het heeft te maken met hoe ES een veld interperteerd. Dit gaat d.m.v. analyzers. Daar heb je een aantal van https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-analyzers.html. Standaard staat hij op standard, volgens de documentatie doet dat het volgende:

The standard analyzer divides text into terms on word boundaries, as defined by the Unicode Text Segmentation algorithm. It removes most punctuation, lowercases terms, and supports removing stop words.

Elastic doet dan het volgende met https://www.google.nl

localhost:9200/index/_analyze?text=https://www.google.nl&analyzer=standard
{
    "tokens": [
        {
            "token": "http",
            "start_offset": 0,
            "end_offset": 4,
            "type": "<ALPHANUM>",
            "position": 0
        },
        {
            "token": "www.google.nl",
            "start_offset": 7,
            "end_offset": 25,
            "type": "<ALPHANUM>",
            "position": 1
        }
    ]
}

Je ziet dat hij afgebroken wordt op niet alphanumerieke karakters (blijkbaar hoort een . daar ook bij dus).

De simpel analyzer doet het volgende:

localhost:9200/index/_analyze?text=https://www.google.nl&analyzer=simple
{
    "tokens": [
        {
            "token": "http",
            "start_offset": 0,
            "end_offset": 4,
            "type": "word",
            "position": 0
        },
        {
            "token": "www",
            "start_offset": 7,
            "end_offset": 10,
            "type": "word",
            "position": 1
        },
        {
            "token": "google",
            "start_offset": 11,
            "end_offset": 22,
            "type": "word",
            "position": 2
        },
        {
            "token": "nl",
            "start_offset": 23,
            "end_offset": 25,
            "type": "word",
            "position": 3
        }
    ]
}

Deze gebruik echt alleen maar letters voor het analyzeren.

De oplossing

De oplossing is om een keyword analyzer op het veld te zetten. Helaas kan dit alleen bij het aanmaken van de index en niet meer achteraf. Je moet dus je index verwijderen en opnieuw opbouwen met de keyword analyzer op het domain veld

In de controller staat die functie, deze kan je aanpassen als volgt

$params = [
  'body' => [
    'mappings' => [
      'domain_stats' => [
        '_source' => [
          'enabled' => TRUE,
        ],
        'properties' => [
          'domain' => [
            'type' => 'string',
            'analyzer' => 'keyword',
          ],
        ],
      ],
    ],
  ],
];

Wanneer je daarna een gewone search doet op domain werkt het.

localhost:9200/index/_search
{  
   "query":{  
      "term":{  
         "domain":"https://www.google.nl"
      }
   }
}
{
    "took": 10,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "failed": 0
    },
    "hits": {
        "total": 1,
        "max_score": 1,
        "hits": [
            {
                "_index": "index",
                "_type": "domain_stats",
                "_id": "1510842681",
                "_score": 1,
                "_source": {
                    "domain": "https://www.google.nl",
                    "googlePSMobileScore": 52,
                    "googlePSMobileUsabilityScore": 100,
                    "googlePSDesktopScore": 63,
                    "mozPDA": 24.48,
                    "mozUPA": 31.57,
                    "date": "2017-11-16T15:31:21+01:00"
                }
            }
        ]
    }
}
localhost:9200/index/_analyze?text=https://www.google.nl&analyzer=keyword
{
    "tokens": [
        {
            "token": "https://www.google.nl",
            "start_offset": 0,
            "end_offset": 25,
            "type": "word",
            "position": 0
        }
    ]
}