GitHub Copilot - Elasticsearch 和 MySQL 单表查询耗时比对

当单表数据库超过百万后,数据库 like '%xxx%' 查询明显变慢,为了对比 Elasticsearch 的效果,将百万级的测试数据导入到 Elasticsearch 中对比看看效果。导入和查询 Elasticsearch 的过程完全通过 GitHub Copilot Chat 辅助编码。

Elasticsearch 环境

使用 Docker Compose 快速搭建环境,compose.yaml 配置如下:

version: "2"
services:
  elasticsearch:
    image: docker.io/bitnami/elasticsearch:8
    ports:
      - '9200:9200'
      - '9300:9300'
    volumes:
      - "elasticsearch_data:/bitnami/elasticsearch"
  kibana:
    image: docker.io/bitnami/kibana:8
    ports:
      - "5601:5601"
    volumes:
      - "kibana_data:/bitnami/kibana"
    depends_on:
      - elasticsearch
volumes:
  elasticsearch_data:
    driver: local
  kibana_data:
    driver: local

参考:

https://github.com/bitnami/containers/tree/main/bitnami/kibana
https://github.com/bitnami/containers/tree/main/bitnami/elasticsearch

数据库 VS Elasticsearch

数据库查询

SQL:

SELECT * FROM itsm_base_enterprisemanagement 
WHERE cname like '%1876%' 
and ctaxcode like '%767%' 
and (ctypeid_name = '6' or ctypeid_name = '16');`

查询结果数:860
查询耗时:3.593s
查询截图:

在这里插入图片描述

Elasticsearch 查询

HTTP:

GET /itsm_base_enterprisemanagement_index/_search
{
  "size": 10000,
  "query": {
    "bool": {
      "must": [
        {
          "wildcard": {
            "cname": "*1876*"
          }
        },
        {
          "wildcard": {
            "ctaxcode": "*767*"
          }
        },
        {
          "bool": {
            "should": [
              {
                "term": {
                  "ctypeid_name": "6"
                }
              },
              {
                "term": {
                  "ctypeid_name": "16"
                }
              }
            ]
          }
        }
      ]
    }
  }
}

部分查询结果:

{
  "took": 78,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 860,
      "relation": "eq"
    },
    "max_score": 5.401209,
    "hits": [
      {
        "_index": "itsm_base_enterprisemanagement_index",
        "_id": "1xY-SIwBGWXLItGpKRZG",
        "_score": 5.401209,
        "_source": {
          "csynflag": "0",
          "cname": "191618767@qq.com",
          "isvalid": "0",
          "cTimeStamp": "2023-12-06 14:53:41",
          "cCreatorId": "191618767@qq.com",
          "cCreateDate": "2023-12-06 14:53:41",
          "cGuid": "191618767@qq.com",
          "cmaintainerid": "191618767@qq.com",
          "ctypeid_name": "6",
          "ctaxcode": "191618767@qq.com",
          "ccrminsertsyn": "0",
          "ccrmupdatesyn": "1",
          "cremark": "191618767@qq.com191618767"
        }
      },

查询结果数:860
查询耗时:155ms
查询截图:

在这里插入图片描述

对比结果: MySQL 比 ES 慢 23 倍

GitHub Copilot 对话过程

<<<GitHub Copilot:

Hi @abel533, how can I help you? I’m powered by AI, so surprises and mistakes are possible. Make sure to verify any generated code or suggestions, and share feedback so that we can learn and improve.

>>>ASK:

JDBC 连接数据库代码。

<<<GitHub Copilot:

要使用 JDBC 连接数据库,您需要以下步骤:

  1. 加载并注册 JDBC 驱动程序
  2. 创建数据库连接
  3. 创建 Statement 对象
  4. 执行 SQL 查询
  5. 处理结果集
  6. 关闭连接

以下是一个简单的示例,该示例使用 JDBC 连接到 MySQL 数据库:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class ESInsert {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/your_database";
        String user = "your_username";
        String password = "your_password";

        try {
            // 1. Load and register driver
            Class.forName("com.mysql.cj.jdbc.Driver");

            // 2. Create connection
            Connection conn = DriverManager.getConnection(url, user, password);

            // 3. Create statement
            Statement stmt = conn.createStatement();

            // 4. Execute SQL query
            // TODO: Add your SQL query here

            // 5. Process the result set
            // TODO: Process your result set here

            // 6. Close connection
            conn.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

请注意,您需要将 your_database,your_username 和 your_password 替换为您的数据库名称,用户名和密码。此外,您可能需要根据您的实际需求添加 SQL 查询和处理结果集的代码。

>>>ASK:

使用 stmt 查询 itsm_base_enterprisemanagement 表的全部数据,根据表的字段在 ES 创建索引,将所有数据插入到 ES 中。

<<<GitHub Copilot:

要将 itsm_base_enterprisemanagement 表的所有数据查询出来,并根据表的字段在 ES 创建索引,然后将所有数据插入到 ES 中,我们可以按照以下步骤进行:

  1. 使用 stmt 查询 itsm_base_enterprisemanagement 表的所有数据。
  2. 获取查询结果的元数据,以获取列名,这些列名将用作 ES 索引的字段。
  3. 创建 ES 索引。
  4. 将查询结果插入到 ES 索引中。

以下是实现这些步骤的 Java 代码:

import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

// 1. Query all data from itsm_base_enterprisemanagement
String query = "SELECT * FROM itsm_base_enterprisemanagement";
ResultSet rs = stmt.executeQuery(query);

// 2. Get the metadata of the result set
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();

// 3. Create ES index
String indexName = "itsm_base_enterprisemanagement_index";
CreateIndexRequest request = new CreateIndexRequest(indexName);

XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
{
    builder.startObject("properties");
    {
        for (int i = 1; i <= columnCount; i++) {
            builder.startObject(rsmd.getColumnName(i));
            {
                builder.field("type", "text");
            }
            builder.endObject();
        }
    }
    builder.endObject();
}
builder.endObject();
request.source(builder);

RestHighLevelClient client = new RestHighLevelClient(
    RestClient.builder(
        new HttpHost("localhost", 9200, "http")
    )
);
CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);

// 4. Insert all data into ES index
while (rs.next()) {
    Map<String, Object> jsonMap = new HashMap<>();
    for (int i = 1; i <= columnCount; i++) {
        jsonMap.put(rsmd.getColumnName(i), rs.getObject(i));
    }

    IndexRequest indexRequest = new IndexRequest(indexName)
        .source(jsonMap);
    IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);
}

// Don't forget to close the connections
rs.close();
stmt.close();
conn.close();
client.close();

请注意,这段代码假设您已经在项目中添加了 Elasticsearch 的 Java 客户端依赖,并且 Elasticsearch 服务器正在本地的 9200 端口上运行。如果不是,请根据实际情况修改代码。

>>>ASK:

针对 ES 的操作不要使用 elasticsearch-rest-high-level-client sdk,使用 elasticsearch-rest-client 8.11 版本的 sdk

<<<GitHub Copilot:

要使用 elasticsearch-rest-client 8.11 版本的 SDK 进行 ES 操作,我们需要对上述代码进行一些修改。以下是修改后的代码:

import org.apache.http.HttpHost;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

// 1. Query all data from itsm_base_enterprisemanagement
String query = "SELECT * FROM itsm_base_enterprisemanagement";
ResultSet rs = stmt.executeQuery(query);

// 2. Get the metadata of the result set
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();

// 3. Create ES index
String indexName = "itsm_base_enterprisemanagement_index";

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

// Create index request
Request createIndexRequest = new Request("PUT", "/" + indexName);
createIndexRequest.setJsonEntity(
    "{\n" +
    "  \"mappings\": {\n" +
    "    \"properties\": {\n" +
    // Add fields to the index
    "    }\n" +
    "  }\n" +
    "}"
);
Response createIndexResponse = restClient.performRequest(createIndexRequest);

// 4. Insert all data into ES index
while (rs.next()) {
    Map<String, Object> jsonMap = new HashMap<>();
    for (int i = 1; i <= columnCount; i++) {
        jsonMap.put(rsmd.getColumnName(i), rs.getObject(i));
    }

    // Create index request
    Request indexRequest = new Request("POST", "/" + indexName + "/_doc");
    indexRequest.setJsonEntity(jsonMap.toString());
    Response indexResponse = restClient.performRequest(indexRequest);
}

// Don't forget to close the connections
rs.close();
stmt.close();
conn.close();
restClient.close();

请注意,这段代码假设您的 Elasticsearch 服务器正在本地的 9200 端口上运行。如果不是,请根据实际情况修改代码。此外,这段代码没有处理异常,您可能需要根据实际需求添加异常处理代码。

>>>ASK:

// Add fields to the index,此处注释的属性根据数据库字段自动生成

<<<GitHub Copilot:

要根据数据库字段自动生成索引属性,我们需要在查询结果集的元数据中获取列名,并将这些列名作为索引的字段。以下是修改后的代码:

// 2. Get the metadata of the result set
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();

// 3. Create ES index
String indexName = "itsm_base_enterprisemanagement_index";

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

StringBuilder mappings = new StringBuilder();
mappings.append("{\n");
mappings.append("  \"mappings\": {\n");
mappings.append("    \"properties\": {\n");

// Add fields to the index
for (int i = 1; i <= columnCount; i++) {
    mappings.append("      \"").append(rsmd.getColumnName(i)).append("\": {\n");
    mappings.append("        \"type\": \"text\"\n");
    mappings.append("      },\n");
}

// Remove the last comma and close the JSON object
mappings.setLength(mappings.length() - 2);
mappings.append("\n    }\n  }\n}");

// Create index request
Request createIndexRequest = new Request("PUT", "/" + indexName);
createIndexRequest.setJsonEntity(mappings.toString());
Response createIndexResponse = restClient.performRequest(createIndexRequest);

这段代码将遍历结果集的元数据,获取每个列的名称,并将这些名称作为 ES 索引的字段。然后,它将创建一个包含这些字段的 ES 索引。

>>>ASK:

type 类型不要固定为 text,根据数据库字段类型进行转换。

<<<GitHub Copilot:

要根据数据库字段类型进行转换,我们需要获取结果集元数据中的每个列的类型,并将这些类型用作 ES 索引的字段类型。以下是修改后的代码:

// 2. Get the metadata of the result set
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();

// 3. Create ES index
String indexName = "itsm_base_enterprisemanagement_index";

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

StringBuilder mappings = new StringBuilder();
mappings.append("{\n");
mappings.append("  \"mappings\": {\n");
mappings.append("    \"properties\": {\n");

// Add fields to the index
for (int i = 1; i <= columnCount; i++) {
    mappings.append("      \"").append(rsmd.getColumnName(i)).append("\": {\n");
    mappings.append("        \"type\": \"").append(convertSqlTypeToESType(rsmd.getColumnType(i))).append("\"\n");
    mappings.append("      },\n");
}

// Remove the last comma and close the JSON object
mappings.setLength(mappings.length() - 2);
mappings.append("\n    }\n  }\n}");

// Create index request
Request createIndexRequest = new Request("PUT", "/" + indexName);
createIndexRequest.setJsonEntity(mappings.toString());
Response createIndexResponse = restClient.performRequest(createIndexRequest);

这段代码将遍历结果集的元数据,获取每个列的名称和类型,并将这些名称和类型作为 ES 索引的字段和类型。然后,它将创建一个包含这些字段和类型的 ES 索引。
请注意,我添加了一个名为 convertSqlTypeToESType 的方法,该方法将 SQL 类型转换为 ES 类型。这是该方法的一个简单实现:

private static String convertSqlTypeToESType(int sqlType) {
    switch (sqlType) {
        case Types.INTEGER:
        case Types.TINYINT:
        case Types.SMALLINT:
        case Types.BIGINT:
            return "integer";
        case Types.FLOAT:
        case Types.REAL:
        case Types.DOUBLE:
        case Types.NUMERIC:
        case Types.DECIMAL:
            return "float";
        case Types.BOOLEAN:
            return "boolean";
        case Types.DATE:
        case Types.TIME:
        case Types.TIMESTAMP:
            return "date";
        default:
            return "text";
    }
}

这个方法根据 SQL 类型返回对应的 ES 类型。如果 SQL 类型不在这个方法处理的范围内,那么默认返回"text"。您可能需要根据实际需求修改这个方法。

>>>ASK:

new Request("POST", "/" + indexName + "/\_doc") 这里能否改为批量插入?

<<<GitHub Copilot:

是的,Elasticsearch REST Client 支持批量插入操作。我们可以使用"_bulk" API 来进行批量插入。以下是修改后的代码:

// 4. Insert all data into ES index
StringBuilder bulkRequestBody = new StringBuilder();
while (rs.next()) {
    Map<String, Object> jsonMap = new HashMap<>();
    for (int i = 1; i <= columnCount; i++) {
        jsonMap.put(rsmd.getColumnName(i), rs.getObject(i));
    }

    // Create index request
    bulkRequestBody.append("{\"index\":{\"_index\":\"").append(indexName).append("\"}}\n");
    bulkRequestBody.append(jsonMap.toString()).append("\n");
}

// Execute bulk request
Request bulkRequest = new Request("POST", "/_bulk");
bulkRequest.setJsonEntity(bulkRequestBody.toString());
Response bulkResponse = restClient.performRequest(bulkRequest);

这段代码将遍历结果集,为每一行数据创建一个索引请求,并将这些请求添加到批量请求的主体中。然后,它将执行批量请求,将所有数据一次性插入到 ES 索引中。

>>>ASK:

批量插入改为每 100 个提交一次

<<<GitHub Copilot:

要实现每 100 条数据提交一次的批量插入,我们可以在遍历结果集时,每当累计到 100 条数据时,就执行一次批量请求。以下是修改后的代码:

// 4. Insert all data into ES index
StringBuilder bulkRequestBody = new StringBuilder();
int count = 0;
while (rs.next()) {
    Map<String, Object> jsonMap = new HashMap<>();
    for (int i = 1; i <= columnCount; i++) {
        jsonMap.put(rsmd.getColumnName(i), rs.getObject(i));
    }

    // Create index request
    bulkRequestBody.append("{\"index\":{\"_index\":\"").append(indexName).append("\"}}\n");
    bulkRequestBody.append(jsonMap.toString()).append("\n");

    count++;

    // Execute bulk request every 100 records
    if (count % 100 == 0) {
        Request bulkRequest = new Request("POST", "/_bulk");
        bulkRequest.setJsonEntity(bulkRequestBody.toString());
        Response bulkResponse = restClient.performRequest(bulkRequest);

        // Clear the bulk request body
        bulkRequestBody.setLength(0);
    }
}

// Execute the remaining requests if there are less than 100
if (bulkRequestBody.length() > 0) {
    Request bulkRequest = new Request("POST", "/_bulk");
    bulkRequest.setJsonEntity(bulkRequestBody.toString());
    Response bulkResponse = restClient.performRequest(bulkRequest);
}

这段代码将遍历结果集,为每一行数据创建一个索引请求,并将这些请求添加到批量请求的主体中。每当累计到 100 条数据时,它就会执行一次批量请求。如果最后还剩下少于 100 条数据,它也会执行一次批量请求,以确保所有数据都被插入到 ES 索引中。

>>>ASK:

itsm_base_enterprisemanagement 表有 100 多万数据,将查询改为流式查询,每次加载一部分,避免内存不足。

<<<GitHub Copilot:

要将查询改为流式查询,我们可以使用 JDBC 的 Statement 对象的 setFetchSize 方法来设置每次从数据库中获取的行数。以下是修改后的代码:

// 1. Query all data from itsm_base_enterprisemanagement
String query = "SELECT * FROM itsm_base_enterprisemanagement";

// Set the fetch size to a reasonable number to avoid memory issues
stmt.setFetchSize(1000);

ResultSet rs = stmt.executeQuery(query);

在这段代码中,我们设置了每次从数据库中获取 1000 行数据。这样,即使 itsm_base_enterprisemanagement 表有 100 多万数据,我们也可以避免一次性加载所有数据导致的内存不足问题。

>>>ASK:

在 mysql jdbc 中,设置 1000 有效吗?是否应该 stmt.setFetchSize(Integer.MIN_VALUE);

<<<GitHub Copilot:

在 MySQL JDBC 驱动中,setFetchSize(Integer.MIN_VALUE)被用来开启流式查询,这样可以避免一次性加载所有数据导致的内存不足问题。这是因为 MySQL JDBC 驱动对 setFetchSize 方法的实现与 JDBC 规范不同。在 JDBC 规范中,setFetchSize 方法的参数表示每次从数据库中获取的行数,但在 MySQL JDBC 驱动中,如果参数为 Integer.MIN_VALUE,则会开启流式查询。

如果你想每次从数据库中获取固定数量的行,例如 1000 行,你可以尝试设置 setFetchSize(1000),但是需要注意的是,这在 MySQL JDBC 驱动中可能不会按预期工作,因为 MySQL JDBC 驱动的实现与 JDBC 规范不同。

所以,如果你正在使用 MySQL JDBC 驱动,并且想要开启流式查询以处理大量数据,你应该使用 stmt.setFetchSize(Integer.MIN_VALUE);

>>>ASK:

如何在 kibana 的 devtool 中查询 itsm_base_enterprisemanagement_index 的数量

<<<GitHub Copilot:

要在 Kibana 的 DevTools 中查询 itsm_base_enterprisemanagement_index 的数量,您可以使用 Elasticsearch 的 count API。以下是查询语句:

GET /itsm_base_enterprisemanagement_index/_count

这个查询将返回 itsm_base_enterprisemanagement_index 索引中的文档数量。

>>>ASK:

查询 itsm_base_enterprisemanagement_index 索引中 cname 字段包含 1876 的所有数据的 cguid

<<<GitHub Copilot:

要查询 itsm_base_enterprisemanagement_index 索引中 cname 字段包含 1876 的所有数据的 cguid,您可以使用 Elasticsearch 的 match 查询。在 Kibana 的 DevTools 中,您可以使用以下查询:

GET /itsm_base_enterprisemanagement_index/_search
{
  "query": {
    "match": {
      "cname": "1876"
    }
  },
  "_source": ["cguid"]
}

这个查询将返回 cname 字段包含 1876 的所有文档的 cguid 字段。

>>>ASK:

上面的查询结果为空,为了验证里面有没有数据,先写个查询,获取该索引 10 条数据。

<<<GitHub Copilot:

要查询 itsm_base_enterprisemanagement_index 索引的前 10 条数据,您可以使用 Elasticsearch 的 size 参数来限制返回的文档数量。在 Kibana 的 DevTools 中,您可以使用以下查询:

GET /itsm_base_enterprisemanagement_index/_search
{
  "size": 10
}

这个查询将返回 itsm_base_enterprisemanagement_index 索引的前 10 条文档。

>>>ASK:

索引中没有任何数据,请检查 ESInsert.java 中是否存在问题?

<<<GitHub Copilot:

首先,我们需要确认以下几点:

  1. 数据库连接信息是否正确?请检查url、user和password是否正确。
  2. 数据库中的itsm_base_enterprisemanagement表是否存在,并且是否有数据?
  3. Elasticsearch服务器是否在运行,并且是否可以通过localhost:9200访问?
  4. 是否有足够的权限在Elasticsearch中创建索引和插入数据?

如果以上所有条件都满足,那么ESInsert.java应该能够正确地从数据库中获取数据并插入到Elasticsearch中。

然而,如果在运行ESInsert.java时抛出了异常,那么可能会在插入数据之前就终止了程序,导致Elasticsearch中没有数据。为了找出可能的问题,你可以检查是否有异常被抛出。在ESInsert.java的main方法中,所有的异常都被捕获并重新抛出为RuntimeException,你可以在重新抛出异常之前打印出异常的详细信息:

} catch (Exception e) {
    e.printStackTrace();
    throw new RuntimeException(e);
}

这样,如果有异常被抛出,你就可以在控制台看到异常的详细信息,这将有助于你找出问题所在。

>>>ASK:

我发现 bug 了,在 jsonMap.toString() 这里,这里没有转换为 JSON,导致插入数据出错。

<<<GitHub Copilot:

确实,jsonMap.toString()并不会将 Map 对象转换为 JSON 格式的字符串,而是将其转换为默认的字符串表示形式,这可能会导致插入数据时出错。为了解决这个问题,我们可以使用一个 JSON 库,如 Gson,来将 Map 对象转换为 JSON 格式的字符串。

首先,需要在项目的 pom.xml 文件中添加 Gson 的依赖:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.9</version>
</dependency>

然后,我们可以在 ESInsert.java 文件中使用 Gson 来转换 Map 对象:

import com.google.gson.Gson;

// ...

public class ESInsert {
    // ...

    public static void main(String[] args) {
        // ...

        Gson gson = new Gson();

        // ...

        while (rs.next()) {
            Map<String, Object> jsonMap = new HashMap<>();
            for (int i = 1; i <= columnCount; i++) {
                jsonMap.put(rsmd.getColumnName(i), rs.getObject(i));
            }

            // Create index request
            bulkRequestBody.append("{\"index\":{\"_index\":\"").append(indexName).append("\"}}\n");
            bulkRequestBody.append(gson.toJson(jsonMap)).append("\n");

            // ...
        }

        // ...
    }

    // ...
}

在这段修改后的代码中,我们创建了一个 Gson 对象,并使用 gson.toJson(jsonMap)来将 Map 对象转换为 JSON 格式的字符串。

>>>ASK:

为了测试插入索引一些数据,如何使用 HTTP 命令清除索引 itsm_base_enterprisemanagement_index 的所有数据?

<<<GitHub Copilot:

要使用 HTTP 命令清除索引 itsm_base_enterprisemanagement_index 的所有数据,您可以使用 Elasticsearch 的 delete API。在 Kibana 的 DevTools 中,您可以使用以下命令:

DELETE /itsm_base_enterprisemanagement_index

这个命令将删除整个 itsm_base_enterprisemanagement_index 索引,包括索引中的所有数据。如果您想再次插入数据,您需要重新创建索引。

>>>ASK:

如何使用 HTTP 请求,模糊查询 cName 包含 1867 的所有数据,查询结果只返回 cGuid?

<<<GitHub Copilot:

要使用 HTTP 请求模糊查询 cName 包含 1867 的所有数据,并且只返回 cGuid,你可以使用 Elasticsearch 的 match 查询和_source 字段来限制返回的字段。在 Kibana 的 DevTools 中,你可以使用以下查询:

GET /itsm_base_enterprisemanagement_index/_search
{
  "query": {
    "match": {
      "cName": "1867"
    }
  },
  "_source": ["cGuid"]
}

这个查询将返回 cName 字段包含 1867 的所有文档的 cGuid 字段。

>>>ASK:

match是模糊匹配吗?为什么查询不到结果?

<<<GitHub Copilot:

Elasticsearch中的match查询实际上是全文本查询,它不仅可以进行模糊匹配,还会对查询的文本进行分析。这意味着,如果你的字段是被分析的(默认情况下,字符串字段会被分析),那么match查询会在执行查询之前,先将查询的文本分割成单个的词条(或称为tokens),然后对每个词条进行查询。 如果你的查询没有返回结果,可能有以下几个原因:

  1. 你查询的文本在字段中不存在。请检查你的查询文本是否正确。
  2. 你的字段是一个未分析的字段。未分析的字段不会被分割成词条,因此match查询可能无法找到匹配的结果。如果你的字段是未分析的,你可能需要使用term查询。
  3. 你的字段是一个数字或日期字段。match查询主要用于文本字段,对于数字或日期字段,你可能需要使用range查询。

如果你确定你的查询文本在字段中应该存在,但是match查询仍然返回空结果,你可能需要检查你的字段是否被正确地分析。你可以使用_analyze API来测试Elasticsearch如何分析你的字段。

>>>ASK:

如何使用 1435 匹配 191435267@qq.com 和 191435268@qq.com?

<<<GitHub Copilot:

要匹配包含"1435"的邮箱地址,如"191435267@qq.com"和"191435268@qq.com",您可以使用 Elasticsearch 的 wildcard 查询。在 Kibana 的 DevTools 中,您可以使用以下查询:

GET /itsm_base_enterprisemanagement_index/_search
{
  "query": {
    "wildcard": {
      "email": "*1435*"
    }
  }
}

这个查询将返回 email 字段包含"1435"的所有文档。

请注意,wildcard 查询可能会比其他类型的查询更消耗资源,因为它需要检查每个字段值是否匹配给定的模式。因此,如果可能,最好使用其他类型的查询,如 match 查询或 term 查询。

>>>ASK:

上述 GET 查询返回结果的 json 结构的各部分是什么含义?为什么没有返回全部匹配的数据?

<<<GitHub Copilot:

Elasticsearch 的 GET 查询返回的 JSON 结构通常包含以下部分:

  • took:查询执行的时间(以毫秒为单位)。
  • timed_out:如果查询在规定的时间内没有完成,则此值为 true。
  • _shards:这部分包含了关于查询涉及的分片的信息,包括总分片数、成功查询的分片数、失败的分片数等。
  • hits:这部分包含了查询结果的详细信息,包括匹配的文档总数、最高得分以及匹配的文档列表。每个文档包含_index(文档所在的索引名)、_type(文档的类型)、_id(文档的 ID)、_score(文档的得分)以及_source(文档的源数据)。
    默认情况下,Elasticsearch 的查询只返回前 10 条匹配的文档,这是为了提高查询效率和响应速度。如果你想返回更多的匹配文档,你可以在查询中添加 size 参数来指定返回的文档数量。例如,以下查询将返回前 100 条匹配的文档:
GET /itsm_base_enterprisemanagement_index/_search
{
  "size": 100,
  "query": {
    "match": {
      "cName": "1867"
    }
  },
  "_source": ["cGuid"]
}

请注意,size 参数的最大值是 10000。如果你需要处理超过 10000 条的结果,你可能需要使用 scroll API 或者 search_after 参数。

>>>ASK:

将 SQL 形式的查询转换为 kibana 中的 HTTP 形式:SELECT * FROM itsm_base_enterprisemanagement WHERE cname like '%1876%' and ctaxcode like '%767%' and (ctypeid_name = '6' or ctypeid_name = '16');

<<<GitHub Copilot:

在 Kibana 的 DevTools 中,您可以使用 Elasticsearch 的查询 DSL(Domain Specific Language)来执行复杂的查询。以下是将您的 SQL 查询转换为 Elasticsearch 查询的示例:

GET /itsm_base_enterprisemanagement_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "wildcard": {
            "cname": "*1876*"
          }
        },
        {
          "wildcard": {
            "ctaxcode": "*767*"
          }
        },
        {
          "bool": {
            "should": [
              {
                "term": {
                  "ctypeid_name": "6"
                }
              },
              {
                "term": {
                  "ctypeid_name": "16"
                }
              }
            ]
          }
        }
      ]
    }
  }
}

这个查询将返回 cname 字段包含"1876",ctaxcode 字段包含"767",并且 ctypeid_name 字段为"6"或"16"的所有文档。

请注意,这个查询假设您的索引名为 itsm_base_enterprisemanagement_index。如果不是,请根据实际情况修改查询。

>>>ASK:

"should"和"must"什么区别?还有那些命令?

<<<GitHub Copilot:

在 Elasticsearch 中,bool 查询可以包含 must,should,must_not 和 filter 这四种类型的子查询:

  • must:这些查询必须匹配,以便文档被包含在结果中。这相当于逻辑"AND"。
  • should:这些查询至少有一个必须匹配,以便文档被包含在结果中。这相当于逻辑"OR"。如果没有 must 或 filter 查询,那么至少一个 should 查询必须匹配。
  • must_not:这些查询必须不匹配,以便文档被包含在结果中。这相当于逻辑"NOT"。
  • filter:这些查询必须匹配,但它们以不评分、缓存方式贡献于结果。这对于过滤和缓存常见的过滤条件非常有用。
    以下是一个包含所有这些子查询的 bool 查询的示例:
GET /_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "title": "Search" } }
      ],
      "filter": [
        { "term": { "status": "published" } },
        { "range": { "publish_date": { "gte": "2015-01-01" }}}
      ],
      "must_not": [
        { "range": { "likes": { "gte": 1000 }}}
      ],
      "should": [
        { "match": { "content": "Elasticsearch" }}
      ]
    }
  }
}

这个查询将返回标题包含"Search",状态为"published",发布日期在"2015-01-01"之后,喜欢的人数少于 1000,以及内容包含"Elasticsearch"的所有文档。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/241268.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

智能客服的应用——政务领域

#本文来源清华大学数据治理研究中心政务热线数智化发展报告 &#xff0c;如有侵权&#xff0c;请联系删除。 面对地方政务热线发展所面临的挑战&#xff0c;数智化转型已经成为了热线系统突破当前发展瓶颈、实现整体提质增效的关键手段。《意见》中也明确指出&#xff0c;政务…

任意文件读取漏洞

使用方法php://filter/readconvert.base64-encode/resourcexxx 任意文件读取漏洞 php://filter/readconvert.base64-encode/resourceflag 在url后边接上 以base64的编码形式 读取flag里面的内容 php://filter/readconvert.base64encode/resourceflag 用kali来解码 创建一个文…

Linux安装Halo(个人网站)

项目简介 1.代码开源:Halo 的项目代码开源在 GitHub 上且处于积极维护状态&#xff0c;截止目前已经发布了 109 个版本。你也可以在上面提交你的问题或者参与代码贡献。2.易于部署:推荐使用 Docker 的方式部署 Halo&#xff0c;便于升级&#xff0c;同时避免了各种环境依赖的问…

C++刷题 -- 哈希表

C刷题 – 哈希表 文章目录 C刷题 -- 哈希表1.两数之和2.四数相加II3.三数之和&#xff08;重点&#xff09; 当我们需要查询一个元素是否出现过&#xff0c;或者一个元素是否在集合里的时候&#xff0c;就要第一时间想到哈希法; 1.两数之和 https://leetcode.cn/problems/two…

Unity中实现ShaderToy卡通火(原理实现篇)

文章目录 前言一、我们在片元着色器中&#xff0c;实现卡通火的大体框架1、使用 noise 和 _CUTOFF 判断作为显示火焰的区域2、_CUTOFF &#xff1a; 用于裁剪噪波范围的三角形3、noise getNoise(uv, t); : 噪波函数 二、顺着大体框架依次解析具体实现的功能1、 uv.x * 4.0; : …

如何进行产品数据分析一——移动应用APP分析方法

如何进行产品数据分析 产品的定义产品分析的构成移动应用APP分析方法AARRR1.流量拆解DAUMAU活跃率拆解流量深度 2.流量引入反作弊算法识别系统&#xff08;量&#xff09;拉新质量评估体系&#xff08;质&#xff09;渠道价值评估体系&#xff08;值&#xff09; 3.流量输出 产…

[MySQL]事务原理之redo log,undo log

&#x1f308;键盘敲烂&#xff0c;年薪30万&#x1f308; 目录 一、log日志文件 &#x1f4d5; 事务执行流程 &#x1f4d5; redo log &#x1f4d5; undo log 二、总结 &#x1f440;再来一遍ACID 1. 原子性&#xff1a;原子性确保事务作为一个整体执行&#xff0c;要么…

D4140交流插座电器漏电断路器的低功耗控制芯片,内置桥式整流器漏电灵敏度可调,采用SOP8和DIP8 的封装形式

D4140 是一种用于交流插座电器漏电断路器的低功耗控制器。这些设备可以检测到接地的危险电流路径&#xff0c;例如设备掉进水中。在发生有害或致命的电击之前&#xff0c;断路器会断开线路。内置有整流桥&#xff0c;齐纳管稳压器&#xff0c;运算放大器&#xff0c;电流基准&a…

【数学建模美赛M奖速成系列】报名流程与论文的基本格式

数学建模美赛M奖速成系列 写在前面报名方式1.官网直接报名2.赛氪软件辅助报名 论文的基本格式摘要模型建立模型求解结果分析与检验模型评价 竞赛的基本注意事项1. 选题后查找资料2. 写作能力和编程能力 历年优秀论文标题与摘要简明扼要善用图表 最后 写在前面 最近&#xff0c…

【Docker】学习笔记(一)三剑客之 docker engine仓库、镜像与容器的基本操作

docker engine安装 ubuntu20.04安装docker教程 docker核心架构 镜像&#xff08;image&#xff09; 一个镜像就代表一个软件服务&#xff08;ubuntu镜像、mysql镜像、redis镜像、mq镜像&#xff09;只读 远程中心仓库&#xff08;repository&#xff09; 中心仓库用来集中存储…

5.1CPU的功能和结构

CPU的功能 1.指令控制。 完成取指令、分析指令和执行指令的操作&#xff0c;即程序的顺序控制。 ⒉操作控制。 一条指令的功能往往是由若干操作信号的组合来实现的。CPU管理并产生由内存取出的每条指令的操作信号&#xff0c;把各种操作信号送往相应的部件&#xff0c;从而控制…

微信小程序:上传图片到别的域名文件下

效果 wxml <!-- 上传照片 --> <view class"addbtn"><view classpic name"fault_photo" wx:for"{{imgs}}" wx:for-item"item" wx:key"*this"><image classweui-uploader_img src"{{item}}"…

程序员必须知晓的11个C++要点-供大家学习研究参考

要点汇集C书中或网站上无法找到的&#xff0c;如&#xff1a;指向成员的指针&#xff0c;这是许多资料中都不愿提到的地方&#xff0c;也是经常出错的地方。希望对大家学习研究有帮助。 要点1: <iostream.h> 还是 <iostream>? 要点2&#xff1a;用引用传递参数时…

若依 ruoyi-vue3+ts-plus+ 宇道 yudao-ruoyi-vue-pro前端显示部门名称

想在 index.vue 上显示列表里对应的部门名称 效果 引入dept import * as DeptApi from "/api/system/dept"; 初始化时 /** 初始化 **/ onMounted(async () > {getList();deptNameList.value await DeptApi.getSimpleDeptList(); }) 加载id 对应的部门名称 …

网络推理之深度学习推理框架

如何选择深度学习推理框架&#xff1f; PyTorch vs LibTorch&#xff1a;网络推理速度谁更快&#xff1f; 高质量C进阶[2]&#xff1a;如何让线性代数加速1000倍&#xff1f; TensorRT: ONNX:

AI日报:人工智能与新材料的发现

文章目录 总览人工智能正在革命性地发现新的或更强的材料&#xff0c;这将改变制造业。更坚韧的合金问题研究解决方案 新材料人工智能存在的挑战方法探索 日本的研究人员正在使用人工智能制造更强的金属合金或发现新材料&#xff0c;并彻底改变制造过程 总览 日本的研究人员开…

【C】⽂件操作

1. 为什么使⽤⽂件&#xff1f; 如果没有⽂件&#xff0c;我们写的程序的数据是存储在电脑的内存中&#xff0c;如果程序退出&#xff0c;内存回收&#xff0c;数据就丢失了&#xff0c;等再次运⾏程序&#xff0c;是看不到上次程序的数据的&#xff0c;如果要将数据进⾏持久化…

鸿蒙原生应用/元服务开发-Stage模型能力接口(二)

ohos.app.ability.AbilityConstant (AbilityConstant)一、说明 AbilityConstant提供Ability相关的枚举&#xff0c;包括设置初次启动原因、上次退出原因、迁移结果、窗口类型等。本模块首批接口从API version 9开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口…

【Java 基础】32 定时调度

文章目录 Timer 类创建 Timer注意事项 ScheduledExecutorService 接口创建 ScheduledExecutorService注意事项 选择合适的定时调度方式Timer 的适用场景ScheduledExecutorService 的适用场景 总结 在软件开发中&#xff0c;定时任务是一种常见的需求&#xff0c;用于周期性地执…

替代升级虚拟化 | ZStack Cloud云平台助力康恩贝核心业务上云

数字经济正加速推动各行各业的高质量升级发展&#xff0c;云计算是数字经济的核心底层基础设施。作为云基础软件企业&#xff0c;云轴科技ZStack 坚持自主创新&#xff0c;自研架构&#xff0c;产品矩阵可全面覆盖数据中心云基础设施&#xff0c;针对虚拟化资源实现纳管、替代和…