5 декември, 2022

Мартин Тошев

Elasticsearch е едно от най-популярните приложения за търсене в днешно време, което се използва в редица приложения (като Wikipedia, Stackoverflow и много други). Базирано е на Lucene библиотеката за търсене и една от основните функционалности, които предлага е JSON-базиран език за писане на заявки, които е изграден над Lucene и предоставя доста лесен механизъм за взаимодействие с Elasticsearch платформата. Поддръжката за SQL добавена в Elasticsearch 6.3 предоставя стандартен механизъм за изпълнение на заявки за търсене и е стъпка напред към по-лесното използване на Elasticsearch от страна на програмистите.

Въпреки че стандарта SQL е разработен основно за работа с релационни бази данни, той е вече успешно реализиран в редица нерелационни бази данни (каквато е и Elasticsearch). Други такива пример включват например и приложения като Apache Spark или Apache Ignite (където SQL е в основата на самото приложение). В тази статия ще разгледаме накратко как работи Elasticsearch SQL.

Предварителен сетъп

За да изпробвате примерите показани в статияте е необходимо да си инстралирате и стартирате локално Elasticsearch (поне версия 6.3). В статията е използван Elasticsearch 7.5. Първо ще създадем posts индекса, който съхранява постове за даден форум. Ще използваме официалния Elasticsearch Java клиент , за да добавим данни в индекса без да указваме експлицитно схема за полетата в индекса (Elasticsearch ще я създаде за нас автоматично в такъв случай).

Необходимо е да създадем Maven проект със зависимост към Elasticsearch Java high level client библиотеката:

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.5.0</version>
</dependency>

Ще създадем 10000 генерирани документа в posts индекса като използваме следния код:

RestHighLevelClient client = new RestHighLevelClient(
    RestClient.builder( new HttpHost("localhost", 9200, "http")));

String[] possibleUsers = new String[] {"Martin", "Jim", "John"};
String[] possibleDates = new String[] {"2019-12-15", "2019-12-16", "2019-12-17"};
String[] possibleMessages = new String[] {
    "Hello, Devstyler !",
    "Cool set of blog posts. We want more !",
    "Elasticsearch SQL is great."};

for (int i = 1; i <= 10000; i++) {
    Map<String, Object> jsonMap = new HashMap<>();
    jsonMap.put("user", possibleUsers[ThreadLocalRandom.current().nextInt(0, 3)]);
    jsonMap.put("date", possibleDates[ThreadLocalRandom.current().nextInt(0, 3)]);
    jsonMap.put("message", possibleMessages[ThreadLocalRandom.current().nextInt(0, 3)]);
    IndexRequest request = new IndexRequest("posts")
        .id(String.valueOf(i)).source(jsonMap);
    client.index(request, RequestOptions.DEFAULT);
}
client.close();

Изпълнение на SQL заявките

Може да използваме Kibana, за да потърсим всички документи, които отговарят на потребителя Martin:

POST /_sql?format=txt
{
    "query": "SELECT * FROM posts where user = 'Martin'"
}

Друг пример е заявка, която брои всички документи, които съдържат ключовата дума:

POST /_sql?format=txt
{
    "query": "SELECT count(*) FROM posts where message like '%Devstyler%'"
}

Ако искаме да изпълним горните заявки през Java приложение имаме няколко опции:

Да използваме Elasticsearch JDBC драйвъра, който обаче е наличен в platinum и enterprise версиите на Elasticsearch;

Да използваме REST клиента на Elasticsearch, които е наличен и в базовата (безплатна) версия.

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-client</artifactId>
    <version>7.5.0</version>
</dependency>

Следния пример връща 10 документа от posts индекса:

RestClient restClient = RestClient.builder(
      new HttpHost("localhost", 9200, "http")).build();

Request request = new Request("POST", "/_sql");
request.setJsonEntity("{\"query\":\"SELECT * FROM posts limit 10\"}");
Response response = restClient.performRequest(request);
String responseBody = EntityUtils.toString(response.getEntity());
System.out.println(responseBody);
restClient.close();

За да видим как в действително се изпълнява дадена SQL заявка от Elasticsearch може да използваме translate функционалността предоставена чрез /_sql/translate адреса в Elasticsearch. Може да изпълним следния код в Kibana, за да видим как в действително SQL заявката се транслира до JSON-базирана Elasticsearch заявка:

POST /_sql/translate
{
    "query": "SELECT * FROM posts limit 10",
    "fetch_size": 10
}

Трябва да получим резултат подобен на следния:

{
  "size" : 10,
  "_source" : {
    "includes" : [
      "message",
      "user"
    ],
    "excludes" : [ ]
  },
  "docvalue_fields" : [
    {
      "field" : "date",
      "format" : "epoch_millis"
    }
  ],
  "sort" : [
    {
      "_doc" : {
        "order" : "asc"
      }
    }
  ]
}

Elasticsearch SQL характеристики

Видяхме как да изпълняваме заявки в Elasticsearch SQL. В действителност имплементацията на SQL в Elasticsearch е доста богата и включва:

  • Различни варианти за форматиране на резултата от SQL заявката (csv, json, yaml и други);
  • Използване на JSON-базирани заявки като филтри към дадена SQL заявка;
  • Команден инструмент за изпълнение на SQL заявка предоставен от elasticsearch-sql-cli инструмента в инсталацията на Elasticsearch;

От гледна точка на самия SQL стандарта следните страница описва в детайли, какво е реализирано като команди, функции и оператори:

https://www.elastic.co/guide/en/elasticsearch/reference/current/sql-commands.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/sql-functions.html

Заключение

В тази статия демонстрирахме как да използваме Elasticsearch SQL, за да взаимодействаме с Elasticsearch платформата. Има голяма вероятност този механизъм да се наложи над JSON-базирания език за писане на заявки. Въпреки това SQL не е алтернатива на JSON-базирания език, а по-скоро допълнение изградено над него.

Мартин Тошев е ИТ консултант, Java ентусиаст и поддръжник на българската Java User Group. Като такъв, неговите интереси са обвързани с всички технологии около Java, както и Cloud Computing technologies, облачни софтуерни архитектури, Enterprise приложения и NoSQL бази данни. 

Тагове: , , , , , , , , , , , , , , ,