De principiante a avanzado: habilidades detalladas de consulta avanzada de Elasticsearch

Elasticsearch es un potente motor de búsqueda de texto completo que utiliza la biblioteca de búsqueda de Lucene para la indexación y búsqueda subyacentes. Elasticsearch proporciona muchas técnicas de consulta avanzadas que pueden ayudar a los usuarios a consultar datos de forma más precisa y eficiente. Este tutorial presentará las técnicas de consulta avanzadas de Elasticsearch y proporcionará código de muestra para ilustrar su uso.

1. consulta booleana

Elasticsearch admite consultas booleanas, incluidos los operadores AND, OR y NOT. Esto permite a los usuarios limitar los resultados de las consultas utilizando múltiples criterios.

Por ejemplo, la siguiente consulta devolverá todos los documentos que coincidan con "foo" y "bar":

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

Además, se puede utilizar una consulta "debería" para coincidir con cualquiera de las condiciones. La siguiente consulta devolverá todos los documentos que coincidan con "foo" o "bar":

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

2. Consulta de rango

Elasticsearch admite consultas de rango, que se pueden utilizar para consultar si un campo está dentro de un rango específico. Hay dos tipos de consultas de rango: rangos numéricos y rangos de fechas.

Por ejemplo, la siguiente consulta devolverá todos los usuarios cuya edad esté entre 18 y 30 años:

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

La siguiente consulta devolverá todos los usuarios con fechas de registro entre el 1 de enero de 2019 y el 1 de enero de 2020:

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

3. Consulta difusa

Elasticsearch admite consultas difusas, que se pueden utilizar para consultar documentos que contienen errores ortográficos o coincidencias aproximadas. Las consultas difusas utilizan algoritmos de coincidencia difusa, como algoritmos de distancia de edición, para encontrar documentos que coincidan estrechamente.

Por ejemplo, la siguiente consulta devolverá documentos que contengan "fox" o "fix":

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

El parámetro "borrosidad" especifica la distancia de edición máxima permitida. En el ejemplo anterior, "borrosidad" es 2, lo que significa que la consulta coincidirá con documentos con una distancia de edición de 1 o 2.

Cuarto, consulta de expresión regular.

Elasticsearch admite consultas de expresiones regulares, que se pueden utilizar para consultar texto que coincida con un patrón específico. Las consultas de expresiones regulares pueden utilizar el tipo de consulta "regexp".

Por ejemplo, la siguiente consulta devolverá documentos que contengan "foo" o "bar":

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

5. Consulta con comodín

Elasticsearch admite consultas con comodines, que se pueden utilizar para consultar texto que contiene patrones comodín. Las consultas con comodines pueden utilizar el tipo de consulta "comodín".

Por ejemplo, la siguiente consulta devolverá documentos que contengan "foo" o "bar":

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

6. Consulta de frase

Elasticsearch admite consultas de frases, que se pueden utilizar para consultar documentos que contienen una o más frases. Las consultas de frases pueden utilizar el tipo de consulta "match_phrase".

Por ejemplo, la siguiente consulta devuelve documentos que contienen la frase "zorro marrón rápido" o "perro perezoso":

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

7. Resaltar

Elasticsearch admite resaltar palabras clave en los resultados de la consulta, lo que se puede utilizar para que los resultados de la consulta sean más fáciles de entender. El resaltado se puede habilitar usando el parámetro "resaltar".

Por ejemplo, la siguiente consulta devolverá documentos que contengan "foo" o "bar" y resaltará la palabra clave en los resultados de la consulta:

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

Ocho, paginación y clasificación.

Elasticsearch admite la paginación y clasificación de los resultados de las consultas. Puede utilizar los parámetros "desde" y "tamaño" para especificar la posición inicial y el número de resultados devueltos. Puede utilizar el parámetro "ordenar" para especificar el método de clasificación.

Por ejemplo, la siguiente consulta devolverá 5 documentos comenzando con el documento 10, ordenados por el campo "edad" en orden ascendente:

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

9. Consulta de agregación

Elasticsearch admite consultas de agregación, que se pueden utilizar para contar y agrupar documentos. Las consultas de agregación se pueden habilitar utilizando el parámetro "aggs".

Por ejemplo, la siguiente consulta devolverá la cantidad de documentos que contienen cada palabra en el campo "contenido":

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

Las anteriores son algunas habilidades de consulta avanzadas de Elasticsearch. A continuación se proporciona un código de muestra para ilustrar su uso.

Diez, código de muestra de Java

El código de muestra es el siguiente:

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"));
        }
    }
}

Aquí utilizamos la API de cliente REST avanzada de Elasticsearch para implementar el código de muestra. En comparación con la API de bajo nivel, la ventaja de usar la API de alto nivel es que es más fácil de usar y el método de uso está más cerca de la orientación a objetos. programación, lo que mejora la eficiencia del desarrollo.

Once, utilizando el marco Spring Boot

Primero, necesitamos agregar las dependencias relevantes. Agregue las siguientes dependencias al ​pom.xml​archivo :

<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>

Entre ellos, ​spring-boot-starter-data-elasticsearch​depende de las dependencias básicas proporcionadas por Spring Boot para la integración con Elasticsearch ​elasticsearch-rest-high-level-client​y depende de la API del cliente REST avanzado de Elasticsearch.

A continuación, creamos una clase principal Spring Boot y le agregamos el siguiente código:

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);
    }

}

Hemos implementado la interfaz ​ElasticsearchDemoApplication​en ​CommandLineRunner​para que los métodos relevantes se ejecuten cuando se inicia la aplicación. En ​run​el método , llamamos métodos para crear un índice, insertar un documento, buscar un documento y eliminar un índice. La implementación específica de estos métodos es la misma que en el código de muestra.

A continuación, podemos ejecutar la aplicación y ver los resultados. Ingrese el siguiente comando en la terminal:

mvn spring-boot:run

A través de esta implementación de Spring Boot, podemos interactuar con Elasticsearch de manera más conveniente sin tener que configurar conexiones y liberar recursos manualmente. Además, Spring Boot también proporciona muchas otras funciones, como la configuración automática y la inyección de dependencia. Esto nos permite centrarnos más en la lógica empresarial sin tener que prestar demasiada atención a la interacción con Elasticsearch.

Resumir

Elasticsearch es un potente motor de búsqueda con muchas técnicas de consulta avanzadas. En el uso real, puede elegir un método de consulta apropiado según las necesidades específicas y utilizar las funciones avanzadas en la declaración de consulta para implementar operaciones de consulta más complejas. Este tutorial presenta los métodos de consulta básicos y las técnicas de consulta avanzadas de Elasticsearch y proporciona los ejemplos de código correspondientes, con la esperanza de ayudar a los lectores a comprender mejor las funciones de consulta de Elasticsearch.

Supongo que te gusta

Origin blog.csdn.net/bairo007/article/details/131958197
Recomendado
Clasificación