跳到主要内容

elasticsearch

简介

Elasticsearch客户端

组件接口

Client.gs

函数原型函数作用
map cluster_info(map opts = nil)Get cluster info.
mixed index(string index, mixed body = nil, map opts = nil)Index a document.
map bulk(string index = nil, mixed body = nil, map opts = nil)Performs multiple indexing or delete operations in a single API call.
map search(string index = nil, map body = nil, map opts = nil)Returns search hits that match the query defined in the request.
mixed get(string index, string id, map opts = nil)Retrieves the document with the specified ID from an index.
mixed indices_create(string index, mixed body = nil, map opts = nil)Creates a new index.
mixed indices_delete(string index, map opts = nil)Deletes an index.

插入性能测试结论:

1.在每条文档数据大小不变化的情况下,从插入用时来分析,bulk插入的平均用时基本在0.26ms到0.32ms之间,而单次插入的平均用时基本在65ms到72ms之间,bulk的性能明显优于单次插入。 2.在每条文档数据大小不变化的情况下,两种插入的用时均未明显受到数量级大小的影响。 3.针对于bulk操作,在数量级不变的情况下,耗时几乎是随着每条文档的数据大小的增加而线性增加。例如数量级为1K的时候,平均每条数据大小为2.86kb,插入耗时为0.322ms,平均每条数据大小为5.5kb,插入耗时为0.556ms, 平均每条数据大小为7.9kb,插入耗时为0.748ms,平均每条数据大小为10.6kb,插入耗时为0.979ms。 4.推测bulk操作的耗时与bulk要操作的数据总量成正相关。

搜索性能测试结论:

在本次测试的数据容量下,从搜索用时来分析,每次搜索的耗时几乎不受到索引当前存储文档数量的影响。

删除性能测试结论:

在测试中发现在使用bulk对数据进行批量删除的过程中,数量级的大小对于删除操作的耗时几乎没有影响。

多协程环境测试结论:

Elasticsearch 在多协程环境下能够较好地利用 CPU 资源,但需要根据硬件资源(CPU 核心数)合理分配协程数量,内存资源尚未成为主要瓶颈。磁盘 I/O 性能在多协程环境下得到了显著优化,但在高并发场景下,磁盘可能成为性能瓶颈。Elasticsearch 在多协程工作环境下表现出较好的性能,能够有效利用 CPU、内存和磁盘资源。

CPU

  • CPU 利用率在合理范围内,没有明显的性能瓶颈。
  • 如果未来数据量或查询负载增加,可以进一步监控 CPU 使用情况。

内存

  • 内存占用在合理范围内,没有明显的内存泄漏或不足。
  • 如果未来数据量增加,可以适当调整 JVM 堆大小(建议不超过物理内存的 50%)。

硬盘

  • 磁盘写入速度和读取速度以及利用率在合理范围内,没有明显的磁盘瓶颈。
  • 如果未来数据量增加,可以进一步监控磁盘 I/O 性能,尤其是写入速度和磁盘队列长度。

样例

public void sample()
{
/**
* 1. 在本地运行Elasticsearch实例:
*
* ```
* curl -fsSL https://elastic.co/start-local | sh
* ```
*
* 2. 设置ES_LOCAL_PASSWORD环境变量(Elasticsearch成功部署后在控制台可查看管理账号密码):
*
* ```
* export ES_LOCAL_PASSWORD=<elastic_password>
* ```
*/

string elastic_password = get_sys_env("ES_LOCAL_PASSWORD");
assert(elastic_password != nil, "Deploy Elasticsearch and execute command: `source elastic-start-local/.env`");

object client = elasticsearch.Elasticsearch("localhost", 9200, {
"basic_auth": sprintf("elastic:%s", elastic_password)
});

// 获取集群信息
map response = client.cluster_info();
printf("client.info(): %O\n", response);

// 重新创建索引
client.indices_delete("my_documents", { "ignore_unavailable": true });
client.indices_create("my_documents");

// 将文档插入索引
response = client.index("my_documents", {
"title": "Work From Home Policy",
"contents": "The purpose of this full-time work-from-home policy is...",
"created_on": "2023-11-02",
});
printf("Id: %s\n", response["_id"]);

array documents = json.parse((string)file.read_all("/data.json", "b"));

array operations = [];
for (map document : documents)
{
operations.push_back({"index": {"_index": "my_documents"}});
operations.push_back(document);
}

// 在一次调用中插入所有文档
response = client.bulk(nil, operations);

// 需要等待Elasticsearch写入
coroutine.sleep(2.0);

// 搜索
response = client.search("my_documents", {
"query": {
"match": {
"name": {
"query": "policy"
}
}
}
});

array results = response.hits.hits ?? [];
if (results.length() > 0)
{
// 按ID获取文档
response = client.get("my_documents", results[0]._id);
}

// 多匹配查询、分页
response = client.search("my_documents", {
"query": {
"multi_match": {
"query": "policy",
"fields": ["name", "summary", "content"],
}
},
"size": 5,
"from": 0,
});
printf("There are a total of %d results:\n", response.hits.total.value);
for (map result : response.hits.hits ?? [])
{
printf(" [%s] score=%.6f " HIC "%s" NOR "\n", result._id, result._score, result._source.summary);
}

// 向查询添加筛选器
response = client.search("my_documents", {
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "work from home",
"fields": ["name", "summary", "content"],
}
}
],
"filter": [
{
"term": {
"category.keyword": {
"value": "sharepoint"
}
}
},
{
"range": {
"updated_at": {
"gte": "2020||/y",
"lte": "2022||/y",
}
}
}
]
}
}
});

// 面搜索
response = client.search("my_documents", {
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "work from home",
"fields": ["name", "summary", "content"],
}
}
]
}
},
"aggs": {
"category-agg": {
"terms": {
"field": "category.keyword",
}
},
"year-agg": {
"date_histogram": {
"field": "updated_at",
"calendar_interval": "year",
"format": "yyyy",
}
}
}
});
printf("Categories:\n");
for (map bucket : response.aggregations["category-agg"].buckets ?? [])
{
printf(" - [%s] %d\n", bucket.key, bucket.doc_count);
}
printf("Years:\n");
for (map bucket : response.aggregations["year-agg"].buckets ?? [])
{
printf(" - [%s] %d\n", bucket.key_as_string, bucket.doc_count);
}
}