От начального уровня до продвинутого: подробные навыки расширенных запросов Elasticsearch

Elasticsearch — мощная система полнотекстового поиска, использующая библиотеку поиска Lucene для базового индексирования и поиска. Elasticsearch предоставляет множество продвинутых методов запросов, которые могут помочь пользователям более точно и эффективно запрашивать данные. В этом руководстве будут представлены расширенные методы запросов Elasticsearch и приведен пример кода, иллюстрирующий их использование.

1. Логический запрос

Elasticsearch поддерживает логические запросы, включая операторы AND, OR и NOT. Это позволяет пользователям ограничивать результаты запроса, используя несколько критериев.

Например, следующий запрос вернет все документы, соответствующие «foo» и «bar»:

GET /_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "content": "foo" }},
        { "match": { "content": "bar" }}
      ]
    }
  }
}

Кроме того, для соответствия любому условию можно использовать запрос «следует». Следующий запрос вернет все документы, соответствующие «foo» или «bar»:

GET /_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "content": "foo" }},
        { "match": { "content": "bar" }}
      ]
    }
  }
}

2. Запрос диапазона

Elasticsearch поддерживает запросы диапазона, которые можно использовать для проверки того, находится ли поле в указанном диапазоне. Существует два типа запросов диапазона: числовые диапазоны и диапазоны дат.

Например, следующий запрос вернет всех пользователей в возрасте от 18 до 30 лет:

GET /_search
{
  "query": {
    "range": {
      "age": {
        "gte": 18,
        "lte": 30
      }
    }
  }
}

Следующий запрос вернет всех пользователей с датами регистрации в период с 1 января 2019 г. по 1 января 2020 г.:

GET /_search
{
  "query": {
    "range": {
      "registered_at": {
        "gte": "2019-01-01",
        "lte": "2020-01-01"
      }
    }
  }
}

3. Нечеткий запрос

Elasticsearch поддерживает нечеткие запросы, которые можно использовать для запроса документов, содержащих орфографические ошибки или приблизительные совпадения. Нечеткие запросы используют алгоритмы нечеткого сопоставления, такие как алгоритмы расстояния редактирования, для поиска документов, которые точно совпадают.

Например, следующий запрос вернет документы, содержащие слова «лиса» или «исправление»:

GET /_search
{
  "query": {
    "fuzzy": {
      "content": {
        "value": "fox",
        "fuzziness": "2"
      }
    }
  }
}

Параметр «размытость» определяет максимально допустимое расстояние редактирования. В приведенном выше примере «нечеткость» равна 2, что означает, что запрос будет соответствовать документам с расстоянием редактирования 1 или 2.

Четвертый, запрос регулярного выражения

Elasticsearch поддерживает запросы регулярных выражений, которые можно использовать для запроса текста, соответствующего указанному шаблону. Запросы регулярных выражений могут использовать тип запроса «regexp».

Например, следующий запрос вернет документы, содержащие «foo» или «bar»:

GET /_search
{
  "query": {
    "regexp": {
      "content": "foo|bar"
    }
  }
}

5. Подстановочный запрос

Elasticsearch поддерживает запросы с подстановочными знаками, которые можно использовать для запроса текста, содержащего шаблоны подстановочных знаков. Запросы с подстановочными знаками могут использовать тип запроса «подстановочный знак».

Например, следующий запрос вернет документы, содержащие «foo» или «bar»:

GET /_search
{
  "query": {
    "wildcard": {
      "content": "foo* OR bar*"
    }
  }
}

6. Фразовый запрос

Elasticsearch поддерживает фразовые запросы, которые можно использовать для запроса документов, содержащих одну или несколько фраз. Фразовые запросы могут использовать тип запроса «match_phrase».

Например, следующий запрос возвращает документы, содержащие фразу «быстрая коричневая лиса» или «ленивая собака»:

GET /_search
{
  "query": {
    "match_phrase": {
      "content": "quick brown fox lazy dog"
    }
  }
}

7. Выделите

Elasticsearch поддерживает выделение ключевых слов в результатах запроса, что можно использовать для облегчения понимания результатов запроса. Подсветку можно включить с помощью параметра «highlight».

Например, следующий запрос вернет документы, содержащие «foo» или «bar», и выделит ключевое слово в результатах запроса:

GET /_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "content": "foo" }},
        { "match": { "content": "bar" }}
      ]
    }
  },
  "highlight": {
    "fields": {
      "content": {}
    }
  }
}

Восемь, нумерация страниц и сортировка

Elasticsearch поддерживает нумерацию страниц и сортировку результатов запросов. Вы можете использовать параметры from и size, чтобы указать начальную позицию и количество возвращаемых результатов. Вы можете использовать параметр sort, чтобы указать метод сортировки.

Например, следующий запрос вернет 5 документов, начиная с документа 10, отсортированных по полю «возраст» в порядке возрастания:

GET /_search
{
  "from": 10,
  "size": 5,
  "query": {
    "match_all": {}
  },
  "sort": [
    { "age": "asc" }
  ]
}

9. Агрегирующий запрос

Elasticsearch поддерживает запросы агрегирования, которые можно использовать для подсчета и группировки документов. Запросы агрегации можно включить с помощью параметра «aggs».

Например, следующий запрос вернет количество документов, содержащих каждое слово в поле «содержание»:

GET /_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "word_count": {
      "terms": {
        "field": "content"
      }
    }
  }
}

Выше приведены некоторые расширенные навыки выполнения запросов в Elasticsearch. Ниже приведен пример кода, иллюстрирующий их использование.

Десять, пример кода Java

Пример кода выглядит следующим образом:

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.apache.http.HttpHost;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder.Field;

public class ElasticsearchDemo {
    
    public static void main(String[] args) throws IOException {
        // 创建客户端
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(new HttpHost("localhost", 9200, "http")));
        
        // 创建索引和映射
        createIndexAndMapping(client);
        
        // 插入文档
        insertDocument(client);
        
        // 查询
        MatchQueryBuilder matchQuery = QueryBuilders.matchQuery("content", "elasticsearch");
        SearchRequest searchRequest = new SearchRequest("my_index");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(matchQuery);
        searchRequest.source(searchSourceBuilder);
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        printSearchResult(response);
        
        // 带有高亮显示的查询
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field(new Field("content").preTags("<em>").postTags("</em>"));
        searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(matchQuery);
        searchSourceBuilder.highlighter(highlightBuilder);
        searchRequest = new SearchRequest("my_index");
        searchRequest.source(searchSourceBuilder);
        response = client.search(searchRequest, RequestOptions.DEFAULT);
        printSearchResultWithHighlight(response);
        
        // 范围查询
        RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("publish_date")
                .from("2020-01-01")
                .to("2021-12-31");
        searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(rangeQuery);
        searchRequest = new SearchRequest("my_index");
        searchRequest.source(searchSourceBuilder);
        response = client.search(searchRequest, RequestOptions.DEFAULT);
        printSearchResult(response);
        
        // 排序
        searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(matchQuery);
        searchSourceBuilder.sort("publish_date");
        searchRequest = new SearchRequest("my_index");
        searchRequest.source(searchSourceBuilder);
        response = client.search(searchRequest, RequestOptions.DEFAULT);
        printSearchResult(response);
        
        // 删除索引
        deleteIndex(client);
        
        // 关闭客户端
        client.close();
    }
    
    private static void createIndexAndMapping(RestHighLevelClient client) throws IOException {
        // 创建索引
        Map<String, Object> settings = new HashMap<>();
        settings.put("number_of_shards", 1);
        settings.put("number_of_replicas", 0);
        Map<String, Object> mapping = new HashMap<>();
        Map<String, Object> properties = new HashMap<>();
        properties.put("title", Map.of("type", "text"));
        properties.put("content", Map.of("type", "text"));
        properties.put("publish_date", Map.of("type", "date"));
        mapping.put("properties", properties);
        client.indices().create(Map.of("index", "my_index", "settings", settings, "mapping", mapping),
                RequestOptions.DEFAULT);
    }

    private static void insertDocument(RestHighLevelClient client) throws IOException {
        // 插入文档
        Map<String, Object> document = new HashMap<>();
        document.put("title", "Elasticsearch Guide");
        document.put("content", "This is a guide to Elasticsearch.");
        document.put("publish_date", "2021-03-01");
        client.index(Map.of("index", "my_index", "id", "1", "body", document), RequestOptions.DEFAULT);
    }

    private static void deleteIndex(RestHighLevelClient client) throws IOException {
        // 删除索引
        client.indices().delete(Map.of("index", "my_index"), RequestOptions.DEFAULT);
    }

    private static void printSearchResult(SearchResponse response) {
        // 打印查询结果
        SearchHits hits = response.getHits();
        System.out.println("Total hits: " + hits.getTotalHits().value);
        System.out.println("Hits:");
        for (SearchHit hit : hits) {
            System.out.println("Id: " + hit.getId());
            System.out.println("Score: " + hit.getScore());
            System.out.println("Title: " + hit.getSourceAsMap().get("title"));
            System.out.println("Content: " + hit.getSourceAsMap().get("content"));
            System.out.println("Publish date: " + hit.getSourceAsMap().get("publish_date"));
        }
    }

    private static void printSearchResultWithHighlight(SearchResponse response) {
        // 打印带有高亮显示的查询结果
        SearchHits hits = response.getHits();
        System.out.println("Total hits: " + hits.getTotalHits().value);
        System.out.println("Hits:");
        for (SearchHit hit : hits) {
            System.out.println("Id: " + hit.getId());
            System.out.println("Score: " + hit.getScore());
            System.out.println("Title: " + hit.getSourceAsMap().get("title"));
            HighlightField highlightField = hit.getHighlightFields().get("content");
            if (highlightField != null) {
                Text[] fragments = highlightField.fragments();
                String content = "";
                for (Text fragment : fragments) {
                    content += fragment;
                }
                System.out.println("Content: " + content);
            } else {
                System.out.println("Content: " + hit.getSourceAsMap().get("content"));
            }
            System.out.println("Publish date: " + hit.getSourceAsMap().get("publish_date"));
        }
    }
}

Здесь мы используем расширенный клиентский API REST Elasticsearch для реализации примера кода.По сравнению с низкоуровневым API, преимущество использования высокоуровневого API заключается в том, что его проще использовать, а метод использования ближе к объектно-ориентированному. программирование, что повышает эффективность разработки.

Одиннадцать, с использованием платформы Spring Boot.

Во-первых, нам нужно добавить соответствующие зависимости. Добавьте в ​pom.xml​файл следующие зависимости:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.15.2</version>
</dependency>

Среди них ​spring-boot-starter-data-elasticsearch​зависит от базовых зависимостей, предоставляемых Spring Boot для интеграции с Elasticsearch, ​elasticsearch-rest-high-level-client​и от расширенного клиентского API REST Elasticsearch.

Далее мы создаем основной класс Spring Boot и добавляем в него следующий код:

import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder.Field;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder.HighlightQuery;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.elasticsearch.client.RestClients;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@SpringBootApplication
public class ElasticsearchDemoApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(ElasticsearchDemoApplication.class, args);
    }

    @Bean
    public RestHighLevelClient client() {
        return RestClients.create(RestClients.createLocalHost()).rest();
    }

    @Override
    public void run(String... args) throws Exception {
        RestHighLevelClient client = client();
        try {
            createIndex(client);
            insertDocument(client);
            searchDocument(client);
            deleteIndex(client);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            client.close();
        }
    }

    private static void createIndex(RestHighLevelClient client) throws IOException {
        // 创建索引
        Settings.Builder settings = Settings.builder()
                .put("index.number_of_shards", 1)
                .put("index.number_of_replicas", 0);
        Map<String, Object> mapping = new HashMap<>();
        Map<String, Object> properties = new HashMap<>();
        properties.put("title", Map.of("type", "text"));
        properties.put("content", Map.of("type", "text"));
        properties.put("publish_date", Map.of("type", "date"));
        mapping.put("properties", properties);
        client.indices().create(Map.of("index", "my_index", "settings", settings, "mapping", mapping),
                RequestOptions.DEFAULT);
    }

    private static void insertDocument(RestHighLevelClient client) throws IOException {
        // 插入文档
        Map<String, Object> document = new HashMap<>();
        document.put("title", "Elasticsearch Guide");
        document.put("content", "This is a guide to
        IndexRequest request = new IndexRequest("my_index")
                .id("1")
                .source(document);
        client.index(request, RequestOptions.DEFAULT);
    }

    private static void searchDocument(RestHighLevelClient client) throws IOException {
        // 搜索文档
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.matchQuery("title", "Elasticsearch"))
                .should(QueryBuilders.matchQuery("content", "guide"));
        sourceBuilder.query(boolQueryBuilder)
                .sort("publish_date", SortOrder.DESC)
                .from(0)
                .size(10)
                .timeout(TimeValue.timeValueSeconds(1))
                .fetchSource(new String[]{"title", "publish_date"}, new String[]{"content"});
        HighlightBuilder highlightBuilder = new HighlightBuilder()
                .field(new Field("title"))
                .highlightQuery(new HighlightQuery().matchQuery(new HashMap<String, Object>() {
   
   {
                    put("title", new HashMap<>());
                }}));
        sourceBuilder.highlighter(highlightBuilder);
        SearchRequest request = new SearchRequest("my_index").source(sourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println("Total hits: " + response.getHits().getTotalHits().value);
        for (SearchHit hit : response.getHits().getHits()) {
            System.out.println("Title: " + hit.getSourceAsMap().get("title"));
            System.out.println("Publish date: " + hit.getSourceAsMap().get("publish_date"));
            System.out.println("Content: " + hit.getHighlightFields().get("title").fragments()[0].string());
            System.out.println("--------------------------");
        }
    }

    private static void deleteIndex(RestHighLevelClient client) throws IOException {
        // 删除索引
        DeleteRequest request = new DeleteRequest("my_index");
        client.indices().delete(request, RequestOptions.DEFAULT);
    }

}

Мы реализовали интерфейс ​ElasticsearchDemoApplication​в ​CommandLineRunner​, чтобы соответствующие методы выполнялись при запуске приложения. В ​run​методе мы вызываем методы создания индекса, вставки документа, поиска документа и удаления индекса. Конкретная реализация этих методов такая же, как в примере кода.

Далее мы можем запустить приложение и увидеть результаты. Введите в терминал следующую команду:

mvn spring-boot:run

Благодаря этой реализации Spring Boot мы можем более удобно взаимодействовать с Elasticsearch без необходимости вручную настраивать соединения и освобождать ресурсы. Кроме того, Spring Boot также предоставляет множество других функций, таких как автоматическая настройка и внедрение зависимостей. Это позволяет нам больше сосредоточиться на бизнес-логике, не уделяя слишком много внимания взаимодействию с Elasticsearch.

Подведем итог

Elasticsearch — мощная поисковая система со множеством продвинутых методов запросов. При фактическом использовании вы можете выбрать подходящий метод запроса в соответствии с конкретными потребностями и использовать расширенные функции в операторе запроса для реализации более сложных операций запроса. В этом руководстве представлены основные и расширенные методы запросов Elasticsearch, а также приведены соответствующие примеры кода, которые помогут читателям лучше понять функции запросов Elasticsearch.

рекомендация

отblog.csdn.net/bairo007/article/details/131958197