Elasticsearch: uso delle match query

Elasticsearch offre uno strumento molto valido per le ricerche testuali. In questo articolo inizieremo a capire come interrogare i campi testuali mediante le query match. Le varie tipologie di query ci permetteranno di raffinare le ricerche per i nostri progetti futuri.

Share

Reading time: 6 minutes

Negli articoli precedenti, ELK Stack: cos’è e a cosa serve, A cosa serve Kibana? e Kibana: esploriamo i dati, abbiamo analizzato alcune caratteristiche dello stack di Elastisearch ed in particolare come visualizzare i dati che abbiamo a disposizione. In questa serie di articoli vedremo invece come si interrogano i dati mediante le API in modo tale che possiamo costruire le nostre applicazioni usando questo potente motore di ricerca.

In particolare, in questo articolo, andremo a vedere alcuni esempi di query basati sul match. Di seguito riportiamo i principali esempi di query trattati nella guida, per un rapido riferimento:

Categoria Tipo Criteri di match Query Match No match
match full-text Trova corrispondenza se una qualsiasi delle keywords di ricerca è presente nel campo (l'analisi viene fatta anche sulle keywords di ricerca) "search better" 1. can I search for better results 1. sear for the box
2. search better please 2. I won the bet
3. you know, for SEARCH 3. there are some things
4. there is a better place out there 4. some people are good at everything
multi_match full-text Per applicare la query di match a più campi key1: "search" key2: "better" se la key1 contiene la parola "search" OPPURE se la key2 contiene la parola "better". N/A
match_phrase full-text Tenterà di estrarre alla frase esatta, nello stesso ordine search better let me search better 1.can I search for better results
2.this is for search betterment
match_phrase_prefix full-text Tenterà di estrarre alla frase esatta in ordine, ma l'ultimo termine corrisponderà come prefisso. search better 1. let me search better can I search for better results
2. this is for search betterment

Creazione dell’ambiente di lavoro

In questi tutorial, utilizzeremo l’ultima versione disponibile di Elasticsearch, ossia la 8.3. Per facilitare la configurazione dell’ambiente di lavoro potete usare il docker che trovate qui. Questo installerà sulla vostra macchina un ELK stack completo che potrete usare anche per altri progetti.

Una volta scaricato il progetto Docker, fatto il build ed avviato, dobbiamo importare i dati che utilizzeremo in questo tutorial. Collegatevi pertanto a Kibana mediante browser all’indirizzo http://localhost:5601/. Vi richiederà l’inserimento delle credenziali che sono quelle di default:

  • username: elastic
  • password: changeme

A questo punto aprite la Console che trovate nel menù Management > Dev Tools. Useremo questo strumento per eseguire le query.

I dati che useremo sono disponibili qui. Prima di caricarli creiamo l’indice employees dalla console con il seguente comando:

PUT employees 

Per gestire in modo opportuno le date definiamo una mappatura per il campo date_of_birth con il seguente comando.

PUT employees/_mapping 
{ "properties": { 
    "date_of_birth": { 
        "type": "date", 
        "format": "dd/MM/yyyy" 
    } 
} }
 

A questo punto possiamo importare i dati. Apriamo una shell e digitiamo il seguente comando.

curl --user elastic:changeme -H 'Content-Type: application/x-ndjson' -XPOST 'localhost:9200/employees/_bulk' --data-binary @employees.json 

Così facendo verrà caricati i dati e create le mappature per i campi che non abbiamo definito precedentemente. In particolare, i campi testuali saranno indicizzati sia come testo (usando l’analyzer standard), sia come keywords, mentre i dati numerici saranno indicizzati come float.

Potete verificare la mappatura con il seguente comando.

GET employees/_mapping 

Ora che abbiamo un indice con i documenti e una mappatura specificata, siamo pronti ad iniziare con le query.

Match Query

La query “match” è una delle query più basilari e comunemente utilizzate in Elasticsearch e funziona come una query full-text. Possiamo usare questa query per cercare testo, numeri o valori booleani.

Cerchiamo la parola “heuristic” contenuta nel campo “phrase” dei documenti che abbiamo caricato in precedenza.

POST employees/_search
{
  "query": {
    "match": {
      "phrase": {
        "query" : "heuristic"
      }
    }
  }
} 

Dei 4 documenti presenti nel nostro indice, solo 2 documenti contengono la parola ” heuristic ” nel campo ” phrase “:

{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 0.6785375,
    "hits": [
      {
        "_index": "employees",
        "_id": "2",
        "_score": 0.6785375,
        "_source": {
          "id": 2,
          "name": "Othilia Cathel",
          "email": "[email protected]",
          "gender": "female",
          "ip_address": "3.164.153.228",
          "date_of_birth": "22/07/1987",
          "company": "Edgepulse",
          "position": "Structural Engineer",
          "experience": 11,
          "country": "China",
          "phrase": "Grass-roots heuristic help-desk",
          "salary": 193530
        }
      },
      {
        "_index": "employees",
        "_id": "4",
        "_score": 0.62577873,
        "_source": {
          "id": 4,
          "name": "Alan Thomas",
          "email": "[email protected]",
          "gender": "male",
          "ip_address": "200.47.210.95",
          "date_of_birth": "11/12/1985",
          "company": "Yamaha",
          "position": "Resources Manager",
          "experience": 12,
          "country": "China",
          "phrase": "Emulation of roots heuristic coherent systems",
          "salary": 300000
        }
      }
    ]
  }
}
 

Cosa succede se vogliamo cercare più di una parola? Utilizzando la stessa query appena eseguita, cerchiamo “heuristic roots help”:

POST employees/_search
{
  "query": {
    "match": {
      "phrase": {
        "query" : "heuristic roots help"
      }
    }
  }
}
 

Questo restituisce lo stesso documento di prima perché, per impostazione predefinita, Elasticsearch tratta ogni parola della query di ricerca con un operatore OR. Nel nostro caso, la query corrisponderà a qualsiasi documento contenente “heuristic” OR “roots” OR “help”.

Modifica del parametro operator

Il comportamento predefinito dell’operatore OR applicato alle ricerche di più parole può essere modificato utilizzando il parametro “operator” passato insieme alla query “match”.

Possiamo specificare il parametro operatore con i valori “OR” o “AND”.

Vediamo cosa succede quando forniamo il parametro operatore “AND” nella stessa query eseguita in precedenza.

POST employees/_search
{
  "query": {
    "match": {
      "phrase": {
        "query" : "heuristic roots help",
        "operator" : "AND"
      }
    }
  }
}
 

Ora i risultati restituiranno un solo documento (documento id=2), poiché è l’unico documento che contiene tutte e tre le parole chiave della ricerca nel campo “phrase”.

minimum_should_match

Per fare un ulteriore passo avanti, si può impostare una soglia per un numero minimo di parole corrispondenti che il documento deve contenere. Ad esempio, se impostiamo questo parametro a 1, la query controllerà tutti i documenti con almeno una parola corrispondente.

Se invece impostiamo il parametro “minium_should_match” a 3, allora tutte e tre le parole devono comparire nel documento per essere classificate come corrispondenti.

Nel nostro caso, la seguente query restituirebbe solo 1 documento (con id=2), poiché è l’unico che corrisponde ai nostri criteri

POST employees/_search
{
  "query": {
    "match": {
      "phrase": {
        "query" : "heuristic roots help",
        "minimum_should_match": 3
      }
    }
  }
}
 

Multi-Match Query

Finora abbiamo trattato le corrispondenze su un singolo campo, cioè abbiamo cercato le parole chiave all’interno di un singolo campo denominato “phrase”.

Ma se avessimo bisogno di cercare delle keywords in più campi di un documento? È qui che entra in gioco la query multi-match.

Proviamo a fare un esempio di ricerca per la keyword “research help” nei campi “position” e “phrase”.

POST employees/_search
{
  "query": {
    "multi_match": {
        "query" : "research help"
        , "fields": ["position","phrase"]
    }
  }
} 

La risposta sarà la seguente:

{
  "took": 21,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 1.2613049,
    "hits": [
      {
        "_index": "employees",
        "_id": "1",
        "_score": 1.2613049,
        "_source": {
          "id": 1,
          "name": "Huntlee Dargavel",
          "email": "[email protected]",
          "gender": "male",
          "ip_address": "58.11.89.193",
          "date_of_birth": "11/09/1990",
          "company": "Talane",
          "position": "Research Associate",
          "experience": 7,
          "country": "China",
          "phrase": "Multi-channelled coherent leverage",
          "salary": 180025
        }
      },
      {
        "_index": "employees",
        "_id": "2",
        "_score": 1.1785964,
        "_source": {
          "id": 2,
          "name": "Othilia Cathel",
          "email": "[email protected]",
          "gender": "female",
          "ip_address": "3.164.153.228",
          "date_of_birth": "22/07/1987",
          "company": "Edgepulse",
          "position": "Structural Engineer",
          "experience": 11,
          "country": "China",
          "phrase": "Grass-roots heuristic help-desk",
          "salary": 193530
        }
      }
    ]
  }
} 

Match Phrase

Match_phrase è un’altra query comunemente usata che, come indica il suo nome, cerca delle frasi in un campo.

Se dovessimo cercare la frase “roots heuristic coherent ” nel campo “phrase” dell’indice, potremmo usare la seguente query:

GET employees/_search
{
  "query": {
    "match_phrase": {
      "phrase": {
        "query": "roots heuristic coherent"
      }
    }
  }
} 

Questo restituirà i documenti con la frase esatta “radici euristiche coerenti”, compreso l’ordine delle parole. Nel nostro caso, abbiamo un solo risultato che corrisponde ai criteri sopra indicati, come mostrato nella risposta seguente.

{
  "took": 32,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1.877336,
    "hits": [
      {
        "_index": "employees",
        "_id": "4",
        "_score": 1.877336,
        "_source": {
          "id": 4,
          "name": "Alan Thomas",
          "email": "[email protected]",
          "gender": "male",
          "ip_address": "200.47.210.95",
          "date_of_birth": "11/12/1985",
          "company": "Yamaha",
          "position": "Resources Manager",
          "experience": 12,
          "country": "China",
          "phrase": "Emulation of roots heuristic coherent systems",
          "salary": 300000
        }
      }
    ]
  }
} 

Parametro Slop

Una caratteristica utile che possiamo utilizzare nella query match_phrase è il parametro “slop”, che ci permette di creare ricerche più flessibili.

Supponiamo di cercare “roots coherent ” con la query match_phrase. Non riceveremmo alcun documento dall’indice dei dipendenti. Questo perché, affinché match_phrase corrisponda, i termini devono essere nell’ordine esatto.

Ora usiamo il parametro slop e vediamo cosa succede:

GET employees/_search
{
  "query": {
    "match_phrase": {
      "phrase": {
        "query": "roots coherent",
        "slop": 1
      }
    }
  }
} 

Con slop=1, la query indica che è possibile spostare una parola per una corrispondenza e quindi riceveremo la seguente risposta. Nella risposta sottostante, si può notare che “radici coerenti” corrisponde al documento “radici euristiche coerenti”. Questo perché il parametro slop consente di saltare 1 termine.

{
  "took": 9,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.7873249,
    "hits": [
      {
        "_index": "employees",
        "_id": "4",
        "_score": 0.7873249,
        "_source": {
          "id": 4,
          "name": "Alan Thomas",
          "email": "[email protected]",
          "gender": "male",
          "ip_address": "200.47.210.95",
          "date_of_birth": "11/12/1985",
          "company": "Yamaha",
          "position": "Resources Manager",
          "experience": 12,
          "country": "China",
          "phrase": "Emulation of roots heuristic coherent systems",
          "salary": 300000
        }
      }
    ]
  }
} 

Match Phrase Prefix

La query match_phrase_prefix è simile alla query match_phrase, ma in questo caso l’ultimo termine della keyword di ricerca viene considerato come un prefisso e viene utilizzato per abbinare qualsiasi termine che inizi con quel prefisso.

Per prima cosa, inseriamo un documento nel nostro indice per capire meglio la query match_phrase_prefix

PUT employees/_doc/5
{
  "id": 4,
  "name": "Jennifer Lawrence",
  "email": "[email protected]",
  "gender": "female",
  "ip_address": "100.37.110.59",
  "date_of_birth": "17/05/1995",
  "company": "Monsnto",
  "position": "Resources Manager",
  "experience": 10,
  "country": "Germany",
  "phrase": "Emulation of roots heuristic complete systems",
  "salary": 300000
} 

Ora applichiamo la query match_phrase_prefix:

GET employees/_search
{
"_source": [ "phrase" ],
  "query": {
    "match_phrase_prefix": {
      "phrase": {
        "query": "roots heuristic co"
      }
    }
  }
} 

Nei risultati sottostanti, possiamo vedere che i documenti con coherent e complete corrispondono alla query. Possiamo anche usare il parametro slop nella query “match_phrase”.

{
  "took": 72,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 3.0871696,
    "hits": [
      {
        "_index": "employees",
        "_id": "4",
        "_score": 3.0871696,
        "_source": {
          "phrase": "Emulation of roots heuristic coherent systems"
        }
      },
      {
        "_index": "employees",
        "_id": "5",
        "_score": 3.0871696,
        "_source": {
          "phrase": "Emulation of roots heuristic complete systems"
        }
      }
    ]
  }
} 

Nota: “match_phrase_query” cerca di corrispondere a 50 espansioni (per impostazione predefinita) dell’ultima parola chiave fornita (co nel nostro esempio). Questo valore può essere aumentato o diminuito specificando il parametro “max_expansions”.

Grazie a questa proprietà di prefisso e alla facilità di impostazione della query match_phrase_prefix, viene spesso utilizzata per la funzionalità di completamento automatico.

Ora cancelliamo il documento appena aggiunto con id=5.

DELETE employees/_doc/5 

More To Explore

Elasticsearch

Elasticsearch: query compound

Elasticsearch offre uno strumento molto valido per effettuare ricerche semplici ma anche complesse. In questo articolo capiremo come inserire più condizioni nella stessa query e modificare il calcolo dello score in base a funzioni personalizzate e ad i valori dei dati.

Elasticsearch

Elasticsearch: uso delle term query

Elasticsearch offre uno strumento molto valido non solo per le ricerche testuali, ma anche per i dati strutturati. In questo articolo capiremo come interrogare i campi strutturati mediante le query term. Le varie tipologie di query ci permetteranno di raffinare le ricerche per i nostri progetti futuri.

Una risposta

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.

Design with MongoDB

Design with MongoDB!!!

Buy the new book that will help you to use MongoDB correctly for your applications. Available now on Amazon!