Resumen de uso simple de ElasticSearch

Tabla de contenido

1. Introducción

2. Conceptos básicos

Tres, integración

Consulta de combinación de cuatro, es

Cinco, interfaz gráfica

Seis, es parte de RESTful-api


1. Introducción

ElasticSearch es un servidor de búsqueda basado en Lucene, que proporciona un motor de búsqueda de texto completo distribuido para múltiples usuarios basado en una interfaz web RESTful. ElasticSearch está orientado a documentos, lo que significa que puede almacenar objetos o documentos completos e indexar el contenido de cada documento para que se pueda buscar (cada campo tiene un índice invertido). En ElasticSearch, puede realizar indexación, búsqueda, clasificación y el filtrado son una de las razones por las que puede realizar búsquedas complejas de texto completo.

Lo anterior está en mandarín. Una gran razón para elegir usar es es que la biblioteca pg tiene un cuello de botella en el rendimiento de las consultas. Debido a razones históricas, SQL necesita realizar una gran cantidad de consultas relacionadas y es más lento. Por lo tanto, es necesario habilitado para almacenar una tabla de todo el negocio Parte redundante de los datos, cuando los datos se actualizan, se sincronizan a es a través de mq, y luego todas las operaciones de consulta anteriores se transfieren a es.

2. Conceptos básicos

Aquí hay algunos conceptos que aparecen a menudo en ES

  • Nodo : una instancia de ES es un nodo y una máquina puede tener varias instancias
  • Índice : una colección de una serie de documentos, donde se almacenan los documentos relacionados. No se recomienda construir demasiados índices para un nodo es, de lo contrario el rendimiento de la búsqueda se verá afectado
  • Fragmento (fragmento): ES es un motor de búsqueda distribuido, cada índice tiene uno o más segmentos, los datos del índice se asignan a cada segmento, el equivalente a un balde de agua, con la taza significa N; el fragmento Existencia es útil para la expansión horizontal. N fragmentos se distribuirán en diferentes nodos de la manera más uniforme posible; cada fragmento es una unidad mínima de trabajo, que contiene parte de los datos, instancia de lucene, indexación completa y capacidad de procesamiento de solicitudes
  • Réplica : se puede entender como un fragmento de respaldo, correspondiente al fragmento principal, cada fragmento puede tener varias copias; el fragmento primario y el fragmento de respaldo no aparecerán en el mismo nodo, y se crea un índice por defecto de 5 fragmentos y uno. copia de seguridad (es decir, 5 copias de seguridad principales + 5 = 10 fragmentos)
  • Tipo (type): En ElasticSearch, un objeto de índice puede almacenar muchos objetos para diferentes propósitos, y el tipo de documento nos permite distinguir fácilmente diferentes objetos en un solo índice.Cada documento puede tener una estructura diferente, pero debemos prestar atención a la diferencia El tipo de documento no se puede establecer en diferentes tipos para el mismo atributo (por ejemplo, en todos los tipos de documento en el mismo índice, un campo llamado título debe tener el mismo tipo); ES6 ya no recomienda una estructura de múltiples tipos de índice único, pero todavía mantiene la compatibilidad. En el momento de ES7, no es compatible en absoluto.
  • Documentos : cada tipo puede contener varios documentos y cada documento contiene varios campos

ES tiene dos números de puerto, 9200 y 9300, 9200 se usa como protocolo http, se usa principalmente para comunicación externa, generalmente cuando lo usamos es 9200; 9300 se usa como protocolo tcp, la comunicación entre jarras es a través del protocolo tcp, y también entre ES los clústeres se comunican a través de 9300.

El tipo de datos del campo no se registra aquí, solo una oración, después de es5.0, el campo de cadena se divide en dos nuevos tipos de datos:

  • texto : realice la segmentación de palabras de acuerdo con el tokenizador y cree un índice invertido basado en el contenido después de la segmentación de palabras
  • palabra clave : sin segmentación de palabras, índice invertido directamente basado en el contenido de la cadena

Si no especificó el tipo de datos del campo al crear el índice , es asignará dinámicamente el campo , es decir, el campo de resultado es numérico antes del almacenamiento y es se asignará a long. Si el resultado posterior se convierte en una cadena, se arrojará mal

Tres, integración

Debido a las necesidades del proyecto, la versión de es seleccionada aquí es 6.7.2, que registra la integración básica y el uso de springboot

Primero introduzca el archivo pom:

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

Luego agregue la información de configuración básica de es en el archivo de configuración

es.ip=
es.port=9200
es.enabled=true
es.index.name=
es.authentication.active=false // 是否需要密码校验
es.user.name=
es.user.password=

es el código de inicio del cliente

    private RestHighLevelClient client;
    private BulkProcessor bulkProcessor;

    @PostConstruct
    public void establishElasticConnection() throws ServiceException {
        if (!appEnv.isEsEnabled()){
            return;
        }

        try {
            if (appEnv.isEsAuthActive()){
                final CredentialsProvider credentialsProvider =
                        new BasicCredentialsProvider();
                credentialsProvider.setCredentials(AuthScope.ANY,
                        new UsernamePasswordCredentials(appEnv.getEsUserName(), appEnv.getEsPassword()));

                RestClientBuilder builder = RestClient.builder(
                        new HttpHost(appEnv.getElasticSearchIp(), appEnv.getElasticSearchPort()))
                        .setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
                            @Override
                            public HttpAsyncClientBuilder customizeHttpClient(
                                    HttpAsyncClientBuilder httpClientBuilder) {
                                return httpClientBuilder
                                        .setDefaultCredentialsProvider(credentialsProvider);
                            }
                        });
                client = new RestHighLevelClient(builder);
            } else {
                client = new RestHighLevelClient(
                        RestClient.builder(
                                new HttpHost(appEnv.getElasticSearchIp(), appEnv.getElasticSearchPort(), "http")));
            }

            // 初始化批量处理器
            initBulkProcessor();

            GetIndexRequest getIndexRequest = new GetIndexRequest(appEnv.getEsIndexName());
            boolean result = client.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
            if (!result) {
                // 指定索引结构并创建
               createIndexStructure(appEnv.getEsIndexName());
            }

        } catch (ElasticsearchException ex){
            throw new ServiceException(ErrorCode.INTERNAL_SERVER_ERROR, new String[] {ex.getMessage()});
        } catch (Exception ex){
            logger.error("Fail to establish ES connection, error:{}", ex.getMessage());
        }
    }


private void createIndexStructure(String indexName){
        CreateIndexRequest request = new CreateIndexRequest(indexName);

        request.settings(Settings.builder()
                .put("index.number_of_shards", 1)
                .put("index.number_of_replicas", 1)
        );

        String[] booleanFields = Constant.ES_BOOLEAN_FIELDS;
        String[] keywordFields = Constant.ES_KEYWORD_TYPE_FIELDS;
        String[] textFields = Constant.ES_TEXT_TYPE_FIELDS;

        Map<String, Object> properties = new HashMap<>();
        Map<String, Object> mapping = new HashMap<>();

        assembleBooleanFields(booleanFields, properties);
        assembleKeywordFields(keywordFields, properties);
        assembleTextFields(textFields, properties);

        mapping.put("properties", properties);
        request.mapping(indexName, mapping);

        try {
            CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
            if (!createIndexResponse.isAcknowledged()) {
                logger.error("Aux costTracking Item Index Creation Failed, createIndexResponse:{}", createIndexResponse.toString());
            }
        } catch (IOException ioEx){
            logger.info("Aux costTracking Item Index Creation Failed");
        }
    }

// 标识该字段既是text又是keyword,es的默认映射也是这种类型
private void assembleTextFields(String[] stringFields, Map<String, Object> properties){
        for (String fieldName : stringFields) {
            Map<String, Object> fieldMeta = new HashMap<>();
            Map<String, Object> Fields = new HashMap<>();
            Map<String, Object> KeyWord = new HashMap<>();

            KeyWord.put(Constant.ES_KEYWORD_TYPE, Constant.ES_KEYWORD_KEYWORD);
            KeyWord.put(Constant.ES_KEYWORD_IGNORE_ABOVE, 256);

            Fields.put(Constant.ES_KEYWORD_KEYWORD, KeyWord);

            fieldMeta.put(Constant.ES_KEYWORD_TYPE, Constant.ES_KEYWORD_TEXT);
            fieldMeta.put(Constant.ES_KEYWORD_FIELDS, Fields);

            properties.put(fieldName, fieldMeta);
        }
    }

// 批量处理器
private void initBulkProcessor() {
        BulkProcessor.Listener listener = new BulkProcessor.Listener() {
            @Override
            public void beforeBulk(long executionId, BulkRequest request) {
                logger.info("Try to bulk {} data", request.numberOfActions());
            }

            @Override
            public void afterBulk(long executionId, BulkRequest request, BulkResponse response) {
                logger.info("{} data bulk success", request.numberOfActions());
            }

            @Override
            public void afterBulk(long executionId, BulkRequest request, Throwable failure) {
                logger.error("{} data bulk failed, reason:{}", request.numberOfActions(), failure);
            }
        };
        BiConsumer<BulkRequest, ActionListener<BulkResponse>> bulkConsumer =
                (request, bulkListener) ->
                        client.bulkAsync(request, RequestOptions.DEFAULT, bulkListener);
        bulkProcessor = BulkProcessor.builder(bulkConsumer, listener)
                .setBulkActions(10000)  // 每添加1w条数据执行一次操作
                .setBulkSize(new ByteSizeValue(5, ByteSizeUnit.MB))  // 每达到5m请求size执行一次操作
                .setFlushInterval(TimeValue.timeValueSeconds(5))  // 每5s执行一次操作
                .setConcurrentRequests(1)  // 允许并发
                .setBackoffPolicy(BackoffPolicy.exponentialBackoff(TimeValue.timeValueMillis(100), 3))  // 100ms后执行,最大请求3次
                .build();
    }

Lo anterior es para especificar el tipo de datos del campo usando el método api. Si la estructura de datos de la mayoría de los índices es similar, puede usar la plantilla de índice para crearla. No se demuestra aquí. Los tipos de mapeo anteriores son los siguientes:

              "properties": {
               "DstIp": {
                  "type": "text",
                  "fields": {
                     "keyword": {
                        "type": "keyword",
                        "ignore_above": 256
                     }
                  }
               },

Con respecto a la adición, eliminación y modificación de es, consulte el documento. Cuando se requiere procesamiento por lotes, se recomienda utilizar el BulkProcessor anterior en lugar de BulkRequest. Parte del procesamiento lógico utilizado en la consulta se presentará a continuación.

Dirección del documento es api: https://www.elastic.co/guide/en/elasticsearch/client/java-rest/6.7/java-rest-high-document-index.html

Consulta de combinación de cuatro, es

Esta es también una de las principales razones por las que elegimos usar es: excelente rendimiento de búsqueda. Aquí solo se introduce la consulta combinada de es: bool query. La consulta bool corresponde a BooleanQuary en lucene. Consta de una o más cláusulas. Cada cláusula tiene un tipo específico. Primero, presentaremos las cuatro combinaciones lógicas de consultas combinadas:

  • must: El documento devuelto debe cumplir las condiciones de la cláusula must y participar en el cálculo de la puntuación
  • filtro: El documento devuelto debe cumplir las condiciones de la cláusula de filtro. Pero no participará en el cálculo de puntuaciones como debe
  • should: El documento devuelto puede cumplir las condiciones de la cláusula should. En una consulta bool, si no hay un must o filter, y hay una o más cláusulas should, se puede devolver siempre que se satisfaga una. El parámetro minimum_should_match define al menos varias cláusulas que deben cumplirse
  • must_nout: el documento devuelto no debe cumplir las condiciones definidas por must_not

El uso de las cuatro combinaciones anteriores puede satisfacer básicamente cualquier consulta compleja. Si una consulta tiene un filtro y un should, se incluye al menos una cláusula should. A continuación, se describe el método de consulta específico: (el nombre de la clase entre paréntesis a continuación corresponde a la api de es)

  • match (matchQuery): consulta de coincidencia, cuando se ejecuta la consulta, el término de búsqueda se segmentará, siempre que el documento coincida con cualquier resultado de segmentación, se considerará una coincidencia
  • match_phrase (matchPhraseQuery): consulta de coincidencia de frase, el término de búsqueda no se segmentará, sino directamente en forma de consulta de frase, siempre que los resultados de segmentación de palabras del campo estén conectados entre sí para que coincida con el término de búsqueda, es considerado satisfecho
  • term (termQuery): consulta exacta, no segmentará el término de búsqueda, pero coincidirá con el campo de destino como un todo, si coincide exactamente, se puede consultar
  • Términos (termsQuery): busque varios valores exactos, la consulta de términos es muy útil para encontrar un valor único, pero por lo general es posible que deseemos buscar varios valores, los términos son una operación de contención y solo uno de ellos puede satisfacerse
  • range (rangeQuery): consulta de rango, generalmente utilizada para campos de número y fecha
  • existe (ExisteQuery): consulta no vacía. Cuando es serializa el documento, el valor nulo no se serializa de forma predeterminada. Si desea consultar datos donde un campo no está vacío, puede usar existe para consultar
  • comodín (wildcardQuery): consulta difusa, similar a la de las bases de datos relacionales, intente usar match o match_phrase para hacer coincidir (con índice)

La diferencia entre termQuery y matchPhraseQuery : El primero no considera el contenido de la segmentación de palabras, y solo coincide con el contenido del campo según el término de búsqueda. Si es igual, se cumple; el segundo combinará las condiciones del campo correspondiente después de la segmentación de palabras, y si se puede combinar en un término de búsqueda y espaciado Es 0, se considera que cumple

Cinco, interfaz gráfica

Para un desarrollo normal, se recomienda utilizar directamente el complemento de cabezal cromado, que es simple y fácil de usar, como:

O use la herramienta de soporte de es kibana, y puede descargarla e instalarla directamente a través de brew en mac: (tenga en cuenta que la versión de kibana y la versión de es deben coincidir, soy kibana de 6.7.0 aquí)

brew install kibana

Tenga en cuenta que kibana se basa en node.js. La dirección es a la que kibana se conecta de forma predeterminada es local. Puede ir al directorio de instalación de kibana para modificar su archivo de configuración y luego ingresar kibana directamente en la línea de comando para iniciarlo. el éxito es el siguiente:

Luego visite localhost: 5601

Las diferentes versiones de kibana tienen diferentes interfaces, por lo que siempre que conozca la consulta básica de la API

 

Seis, es parte de RESTful-api

1. Eliminar índice: curl -XDELETE http: // xxx: 9200 / aux_tracking_item-team4

Admite regular, como curl -XDELETE http: // xxx: 9200 / * _ tracking_item-team4

2. Ver el resultado de la segmentación de palabras de un determinado campo de datos: GET / $ {index} / $ {type} / $ {id} / _ termvectors? Fields = $ {fields_name}

3. Interfaz de segmentación de palabras de prueba: post _analyze

{
  "analyzer": "standard",
  "text": "hello world"
}

 

 

Supongo que te gusta

Origin blog.csdn.net/m0_38001814/article/details/109415240
Recomendado
Clasificación