Funcțiile bazate pe locație sunt destul de frecvente în aplicațiile din zilele noastre. Aceste caracteristici ar putea părea complicate, dar pot fi de fapt implementate destul de ușor cu Elasticsearch.

Elasticsearch este o bază de date NoSQL cu o structură bazată pe documente. Este adesea folosit ca motor de căutare. De asemenea, oferă propria sintaxă și multe instrumente care vă ajută căutarea să fie cât mai flexibilă.

În acest articol vă voi arăta o modalitate simplă de a căuta prin geolocalizare, obținând o listă a orașelor după intervalul de coordonate.

Cum se instalează Elasticsearch

Cum sa configurati cautarea geografica in aplicatia dvs cu Elasticsearch

Puteți găsi un instrument ușor de urmat ghid de instalare pe site-ul Elasticsearch. În momentul în care scriu acest articol, foloseam Elasticsearch versiunea 7.4.2.

Rețineți că Elasticsearch a făcut multe modificări în versiunile recente, una dintre ele fiind eliminarea tipurilor de cartografiere. Deci, dacă utilizați o altă versiune a Elasticsearch, este posibil ca unele lucruri să nu funcționeze complet.

ad-banner

După ce ați terminat instalarea, nu uitați să rulați serviciul Elasticsearch, pe care îl subliniază clar în ghidul de instalare (pentru Linux, faceți acest lucru ./bin/elasticsearch ).

Asigurați-vă că elasticearch-ul dvs. rulează utilizând o solicitare GET în portul 9200 al mașinii dvs. locale, astfel: GET http://localhost:9200

Cum să vă faceți indexul Elasticsearch

Un index este similar cu tabelul dintr-o bază de date obișnuită. Pentru acest exemplu, să facem un index numit cities care va conține datele noastre.

Să definim, de asemenea, un model simplu pentru datele noastre:

  • id : keyword pentru identificatorul nostru
  • name : text pentru numele orașului
  • coordinate : geo_point pentru a stoca coordonatele orașului nostru (îngrijite, au deja acest tip de date)

În Elasticsearch, creăm indexul transformând o buclă într-un API. În cazul nostru, solicitarea noastră va fi astfel:

PUT http://localhost:9200/cities
{
    "settings": {
        "number_of_shards": 1,
        "number_of_replicas": 1
    },
    "mappings": {
        "properties": {
            "id": {
                "type": "keyword"
            },
            "name": {
                "type": "text"
            },
            "coordinate": {
                "type": "geo_point"
            }
        }
    }
}

Când ați folosit acea buclă, ar trebui să primiți un răspuns de acest gen pentru a verifica dacă indexul dvs. a fost creat:

{
    "acknowledged": true,
    "shards_acknowledged": true,
    "index": "cities"
}

Bine făcut! Acum indexul dvs. este gata de utilizare. Să mergem mai departe și să ne jucăm cu noul nostru index creat.

Cum să populați date Elasticsearch

Acum vom completa indexul Elasticsearch cu documente. Dacă nu sunteți familiarizați cu acest termen, trebuie doar să știți că este foarte similar cu rândurile dintr-o bază de date SQL.

În Elasticsearch, este posibil să stocați date care nu se potrivesc cu schema noastră predefinită. Dar nu vom face asta aici – în schimb vom insera date care se potrivesc schemei noastre predefinite.

Deoarece vom introduce mai multe date simultan, vom folosi fișierul în vrac API oferit de Elasticsearch care permite inserări multiple într-un singur apel API.

În exemplul de mai jos, voi introduce 9 orașe în indexul meu. Simțiți-vă liber să adăugați mai multe dacă doriți.

POST 'http://localhost:9200/cities/_bulk

{ "index":{"_index": "cities" } }
{ "id": 1, "name": "Jakarta", "coordinate": {  "lat": -6.2008, "lon": 106.8456}}
{ "index":{"_index": "cities" } }
{ "id": 2, "name": "Tokyo", "coordinate": {  "lat": 35.6762, "lon": 139.6503} }
{ "index":{"_index": "cities" } }
{ "id": 3, "name": "Hong Kong", "coordinate": {  "lat": 22.3193, "lon": 114.1694} }
{ "index":{"_index": "cities" } }
{ "id": 4, "name": "New York", "coordinate": {  "lat": 40.7128, "lon": -74.0060} }
{ "index":{"_index": "cities" } }
{ "id": 5, "name": "Paris", "coordinate": {  "lat": 48.8566, "lon": 2.3522} }
{ "index":{"_index": "cities" } }
{ "id": 6, "name": "Bali", "coordinate": {  "lat": -8.3405, "lon": 115.0920} }
{ "index":{"_index": "cities" } }
{ "id": 7, "name": "Berlin", "coordinate": {  "lat": 52.5200, "lon": 13.4050} }
{ "index":{"_index": "cities" } }
{ "id": 8, "name": "San Fransisco", "coordinate": {  "lat": 37.7749, "lon": -122.4194} }
{ "index":{"_index": "cities" } }
{ "id": 9, "name": "Beijing", "coordinate": {  "lat": 39.9042, "lon": 166.4074} }

Sarcina utilă ar putea părea ciudată, deoarece este într-un format incorect JSON, dar nu vă faceți griji – se presupune că este conceput în acest fel.

Apoi ar trebui să vă răspundă cu un răspuns similar cu acesta:

{
    "took": 72,
    "errors": false,
    "items": [
        //will contains item for each data inserted
        ...
    ]
}

Cum să interogați documentele dvs. Elasticsearch

Lasă aventurile să înceapă
Fotografie de Chris Lawton / Unsplash

Acum vine partea interesantă. Vom face câteva interogări cu documentele pe care le-am inserat înainte.

Elasticsearch acceptă multe tipuri de sintaxă pentru căutarea interogărilor. De asemenea, are căutare de tip geolocație, cu care ne vom juca astăzi.

Putem pur și simplu să căutăm orașele noastre cu o buclă de acest fel:

POST 'http://localhost:9200/cities/_search

{
  "query": {
    "bool": {
      "filter": {
        "geo_distance": {
          "distance": "10km",
          "coordinate": {
            "lat": 37.76,
            "lon": -122.42
          }
        }
      }
    }
  }
}

Această interogare ar trebui să-mi dea San Francisco, iar coordonatele 37.7749 și -122.4194 ar trebui să fie pe o rază de distanță de 10 km față de coordonatele noastre (prin amabilitatea Google).

{
    "took": 7,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 1,
            "relation": "eq"
        },
        "max_score": 0.0,
        "hits": [
            {
                "_index": "cities",
                "_type": "_doc",
                "_id": "eKPspHYBivyIhfWHb2vl",
                "_score": 0.0,
                "_source": {
                    "id": 8,
                    "name": "San Fransisco",
                    "coordinate": {
                        "lat": 37.7749,
                        "lon": -122.4194
                    }
                }
            }
        ]
    }
}

Felicitări! Acum aveți propriul motor de căutare a locației.
Dar să experimentăm un pic mai mult. Să presupunem că doriți să obțineți mai multe orașe în acea locație.

Să încercăm să extindem distanța la 4500 km schimbând sarcina utilă:

{
  "query": {
    "bool": {
      "filter": {
        "geo_distance": {
          "distance": "4500km",
          "coordinate": {
            "lat": 37.76,
            "lon": -122.42
          }
        }
      }
    }
  }
}

Și ar trebui să obțineți acest răspuns:

{
    "took": 8,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 2,
            "relation": "eq"
        },
        "max_score": 0.0,
        "hits": [
            {
                "_index": "cities",
                "_type": "_doc",
                "_id": "dKPspHYBivyIhfWHb2vl",
                "_score": 0.0,
                "_source": {
                    "id": 4,
                    "name": "New York",
                    "coordinate": {
                        "lat": 40.7128,
                        "lon": -74.0060
                    }
                }
            },
            {
                "_index": "cities",
                "_type": "_doc",
                "_id": "eKPspHYBivyIhfWHb2vl",
                "_score": 0.0,
                "_source": {
                    "id": 8,
                    "name": "San Fransisco",
                    "coordinate": {
                        "lat": 37.7749,
                        "lon": -122.4194
                    }
                }
            }
        ]
    }
}

Oferă două rezultate: New York și San Fransisco. Rezultatele arată corect, dar poziționarea ar putea fi puțin ciudată. San Fransisco ar trebui să vină pe primul loc, deoarece este mai aproape, nu?

Nu exact, deoarece ceea ce facem este doar filtrarea. Interogarea noastră este doar o filtrare și nu-i pasă care dintre ele este cea mai apropiată de dvs.

Dar dacă vrem să facem unele calcule pentru a arăta ce locații ar putea fi cele mai apropiate? Nu vă faceți griji, Elasticsearch poate face și asta. Putem folosi un tip de interogare numită interogare de scor funcțional.

Cum se folosește o interogare de scor funcțional în Elasticsearch

Elasticsearch calculează (punctează) ce documente va arăta utilizatorului. Prin utilizarea interogări de scor funcțional putem modifica acel scor astfel încât să putem determina ce documente trebuie returnate.

Aici vom folosi funcția de interogare de descompunere. Există trei tipuri de funcții de descompunere: exp, liniară și gauss. Fiecare dintre ele are comportamente diferite.

1611526207 885 Cum sa configurati cautarea geografica in aplicatia dvs cu Elasticsearch
Imagine sursă

Cea pe care o vom folosi aici este funcția de tip liniar. De asemenea, vom specifica coordonatele împreună cu decalajul și scala.

POST 'http://localhost:9200/cities/_search

{
  "query": {
    "function_score": {
      "functions": [
        {
          "linear": {
            "coordinate": {
              "origin": "37, -122",
              "offset": "100km",
              "scale":"2500km"
            }
          }
        }
      ],
       "min_score":"0.1"
    }
  }
}

Acum, ar trebui să obținem rezultatele ordonate după cel mai mare scor.

{
    "took": 32,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 2,
            "relation": "eq"
        },
        "max_score": 1.0,
        "hits": [
            {
                "_index": "cities",
                "_type": "_doc",
                "_id": "eKPspHYBivyIhfWHb2vl",
                "_score": 1.0,
                "_source": {
                    "id": 8,
                    "name": "San Fransisco",
                    "coordinate": {
                        "lat": 37.7749,
                        "lon": -122.4194
                    }
                }
            },
            {
                "_index": "cities",
                "_type": "_doc",
                "_id": "dKPspHYBivyIhfWHb2vl",
                "_score": 0.19508117,
                "_source": {
                    "id": 4,
                    "name": "New York",
                    "coordinate": {
                        "lat": 40.7128,
                        "lon": -74.0060
                    }
                }
            }
        ]
    }
}

Și asta o încheie!

Concluzie

În acest articol, am prezentat cum să implementăm căutarea bazată pe locație cu Elasticsearch. Dar acesta nu este sfârșitul – ceea ce am arătat aici este doar suprafața a ceea ce puteți face.

Sper că ți s-a părut interesant și util acest articol. Dacă da, continuați să aflați mai multe despre aceasta și încercați să experimentați combinând scorul funcțional. Va fi distractiv, promit.

Fiți mereu curioși și veți învăța ceva nou.