【问题标题】:ElasticSearch search performanceElasticSearch 搜索性能
【发布时间】:2019-07-16 07:52:18
【问题描述】:

我正在开发一个类似于购物车的应用程序,我们在其中存储产品及其元数据 (JSON),并且我们期望更快的搜索结果。 (预期的搜索结果应包含在产品 JSON 文档中任何位置具有搜索字符串的文档)

我们选择了 ElasticSearch(AWS 服务)来存储完整的产品 JSON。我们认为这对我们更快的搜索结果很有帮助。

但是当我尝试测试我的搜索端点时,单个请求需要 2 秒以上,如果我使用 Jmeter 发出 100 个并行请求,它会继续增加到 30 秒。 (这些查询时间来自应用程序日志,而不是来自 Jmeter 响应。)

这是我存储在 ElasticSearch 中的示例产品 JSON 和示例搜索字符串。

我认为我们以错误的方式使用 ES,请帮助我们以正确的方式实现它。

产品 JSON:

 {
  "dealerId": "D320",
  "modified": 1562827907,
  "store": "S1000",
  "productId": "12345689",
  "Items": [
    {

      "Manufacturer": "ABC",
      "CODE": "V22222",
      "category": "Electronics",
      "itemKey": "b40a0e332190ec470",
      "created": 1562828756,
      "createdBy": "admin",
      "metadata": {
        "mfdDate": 1552828756,
        "expiry": 1572828756,
        "description": "any description goes here.. ",
        "dealerName": "KrishnaKanth Sing, Bhopal"
      }
    }
  ]
}

搜索字符串:

krishna

更新: 我们每天收到多种产品的库存(具有不同 productIds 的单独 JSON),我们将它们存储在按日期索引的索引中(例如 products_20190715)。

在搜索时,我们正在搜索 products_* 索引。

我们正在使用JestClient 库从我们的SpringBoot 应用程序与ES 通信。

示例搜索查询:

    {
  "query": {
    "bool": {
      "must": [
        {
          "bool": {
            "must": [
              {
                "simple_query_string": {
                  "query": "krishna*",
                  "flags": -1,
                  "default_operator": "or",
                  "lenient": true,
                  "analyze_wildcard": false,
                  "all_fields": true,
                  "boost": 1
                }
              }
            ],
            "disable_coord": false,
            "adjust_pure_negative": true,
            "boost": 1
          }
        }
      ],
      "filter": [
        {
          "bool": {
            "must": [
              {
                "bool": {
                  "should": [
                    {
                      "match_phrase": {
                        "category": {
                          "query": "Electronics",
                          "slop": 0,
                          "boost": 1
                        }
                      }
                    },
                    {
                      "match_phrase": {
                        "category": {
                          "query": "Furniture",
                          "slop": 0,
                          "boost": 1
                        }
                      }
                    },
                    {
                      "match_phrase": {
                        "category": {
                          "query": "Sports",
                          "slop": 0,
                          "boost": 1
                        }
                      }
                    }
                  ],
                  "disable_coord": false,
                  "adjust_pure_negative": true,
                  "boost": 1
                }
              }
            ],
            "disable_coord": false,
            "adjust_pure_negative": true,
            "boost": 1
          }
        },
        {
          "bool": {
            "disable_coord": false,
            "adjust_pure_negative": true,
            "boost": 1
          }
        }
      ],
      "disable_coord": false,
      "adjust_pure_negative": true,
      "boost": 1
    }
  },
  "sort": [
    {
      "modified": {
        "order": "desc"
      }
    }
  ]
}

【问题讨论】:

  • 您需要更详细地了解如何将此 JSON 存储为弹性文档。它在问题中的呈现方式,似乎您可能只有一个文档......?
  • @JamesThorpe,我已经更新了我的原始帖子。
  • @VenkatPapana 你能提供你的 ES JSON 查询吗
  • @AmitKhandelwal,更新了原帖中的查询

标签: elasticsearch amazon-elasticsearch jest-client


【解决方案1】:

您的 elasticsearch 查询存在几个问题。

  1. 将每天的产品存储在不同的索引中是您的设计选择,我不知道,但如果它是一小部分产品,那么它没有意义并且可能导致性能问题,就像现在这些产品将存储在不同的较小分片中,这会增加您的搜索时间,而不是在单个分片中搜索它们,显然如果数据太大,那么拥有单个分片也会影响性能,但该分析您需要相应地做和设计您的系统,我们可以在这方面为您提供帮助。

  2. 现在让我们来看看您的查询,首先,您使用的是通配符查询,无论如何速度都很慢,请阅读 Elasticsearch 创始人自己评论的这篇文章 :-) 并且还提供了使用 n 的解决方案-grams 标记而不是通配符查询,我们也在生产中使用它来搜索部分术语。

  3. 您的查询的第三个问题是您在搜索查询中使用了"all_fields": true,这将在搜索期间包含索引中的所有字段,这是一项非常昂贵的事情 并且您应该只在搜索中包含相关字段。

我敢肯定,即使您不更改第一个(设计更改)但在查询中合并其他 2 个更改,它仍然会大大提高您的查询性能。

愉快的调试和学习。

【讨论】:

  • 感谢 Amit,1) 选择每日索引的原因:您是对的,今天我们的商店有几百种产品,但我们希望将来为多个商店使用相同的实例 2) 我将尝试 n-gram 3) 我的客户期望所有结果在产品 JSON 文档中的任何位置都有搜索字符串
  • @VenkatPapana 感谢您的澄清,搜索字符串很好(通常全文搜索是这样的),但是您在这里尝试实现的是子字符串搜索,这是非常昂贵的搜索。您的客户想要substring 搜索您产品搜索中的所有单词?请确认,因为在所有字段中进行子字符串搜索没有意义。像 id 字段、日期字段等,可以为品牌名称、磁贴等执行此操作,
  • 你是正确的,阿米特,特定字段需要子字符串搜索,如产品代码、id(它们维护内部自定义代码;用于通信 btw 经销商和商店)也适用于您所说的品牌等少数其他字段.我刚刚从我的搜索字符串中删除了* wild char,我看到查询运行时有很多改进(30-50%)。
  • @VenkatPapana,这是个好消息,正如我之前在回答中所说的那样,通过第 2 点和第 3 点中提到的更改,您应该能够获得重大的性能提升。请不要忘记投票并接受我的回答:-)
  • 当然@Amit,你能告诉我如何指定少数字段的子字符串搜索和剩余字段的常规单词搜索吗?
【解决方案2】:

使用后处理器 JSON 提取器并获取您需要输入的数据模式作为搜索字符串。

将 JSON 表达式和匹配编号指定为 0 以随机获取模式,1 代表第一个数据,2nd 代表第二个数据,依此类推。因此,您已使搜索字符串动态化。 这将复制真实场景,因为每个用户不会搜索相同的字符串。

当您在服务器上放置更多顺序/并发用户时,从每个请求获得响应的时间逐渐增加是正常的。但是您需要关注的是来自服务器的故障以及摘要报告中请求的平均时间。

通常,作为标准,请求的响应时间不应超过 10 秒。(取决于公司和产品类型)。请注意,Jmeter 的默认超时时间约为 21 秒。如果请求时间超过此时间,它将自动失败(如果在线程组中禁用了“延迟线程创建直到需要”)。但是您可以在 Jmeter 中的每个请求的高级选项卡中断言预期值。

【讨论】:

  • 感谢 Arjun 的回复,但我不是要编写 Jmeter 测试和计算响应指标;我想了解为什么我的 ES 搜索查询需要更多时间和方式来优化它。
  • 请让您的问题更清楚。我认为您不想要关于如何加载测试的答案,而是如何修复它或如何优化它。
  • 当然。谢谢阿琼
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
  • 1970-01-01
  • 2012-10-09
  • 1970-01-01
  • 2021-04-21
  • 1970-01-01
相关资源
最近更新 更多