【问题标题】:ElasticSearch query is slow and first query always takes too much timeElasticSearch 查询很慢,第一次查询总是花费太多时间
【发布时间】:2021-02-11 15:27:46
【问题描述】:

我是 elasticsearch 的新手,当我应该匹配多个搜索词以及匹配嵌套文档时,我的查询速度很慢,基本上第一次查询需要 7-10 秒,之后需要 5-6 秒,因为elasticsearch 缓存,但仅匹配的非嵌套对象的查询工作速度很快,即在 100 毫秒内。

我在具有 250GB RAM 和 500GB 磁盘空间的 aws 实例中运行弹性搜索,我有一个模板和 204 个索引,在单个节点中索引了大约 1.07 亿个文档,每个索引有 2 个分片,我保留了 30GB堆大小。

以下是我的内存使用情况:

我可以拥有超过 50k 的嵌套对象,因此我将长度增加到 500k,搜索此嵌套对象需要太多时间,并且对嵌套以外的字段的任何 OR(应该匹配)操作也需要时间,有什么办法吗我可以提高嵌套对象的查询性能吗?或者我的配置有什么问题吗? 有什么方法可以让第一次查询也更快?

{
  "index_patterns": [
    "product_*"
  ],
  "template": {
    "settings": {
      "index.store.type": "mmapfs",
      "number_of_shards":2,
      "number_of_replicas": 0,
      "index": {
        "store.preload": [
          "*"
        ],
        "mapping.nested_objects.limit": 500000,
        "analysis": {
          "analyzer": {
            "cust_product_name": {
              "type": "custom",
              "tokenizer": "standard",
              "filter": [
                "lowercase",
                "english_stop",
                "name_wordforms",
                "business_wordforms",
                "english_stemmer",
                "min_value"
              ],
              "char_filter": [
                "html_strip"
              ]
            },
            "entity_name": {
              "type": "custom",
              "tokenizer": "standard",
              "filter": [
                "lowercase",
                "english_stop",
                "business_wordforms",
                "name_wordforms",
                "english_stemmer"
              ],
              "char_filter": [
                "html_strip"
              ]
            },
            "cust_text": {
              "type": "custom",
              "tokenizer": "standard",
              "filter": [
                "lowercase",
                "english_stop",
                "name_wordforms",
                "english_stemmer",
                "min_value"
              ],
              "char_filter": [
                "html_strip"
              ]
            }
          },
          "filter": {
            "min_value": {
              "type": "length",
              "min": 2
            },
            "english_stop": {
              "type": "stop",
              "stopwords": "_english_"
            },
            "business_wordforms": {
              "type": "synonym",
              "synonyms_path": "<some path>/business_wordforms.txt"
            },
            "name_wordforms": {
              "type": "synonym",
              "synonyms_path": "<some path>/name_wordforms.txt"
            },
            "english_stemmer": {
              "type": "stemmer",
              "language": "english"
            }
          }
        }
      }
    },
    "mappings": {
      "dynamic": "strict",
      "properties": {
        "product_number": {
          "type": "text",
          "analyzer": "keyword"
        },
        "product_name": {
          "type": "text",
          "analyzer": "cust_case_name"
        },
        "first_fetch_date": {
          "type": "date",
          "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||yyyy-MM||yyyy"
        },
        "last_fetch_date": {
          "type": "date",
          "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||yyyy-MM||yyyy"
        },
        "review": {
          "type": "nested",
          "properties": {
            "text": {
              "type": "text",
              "analyzer": "cust_text"
            },
            "review_date": {
              "type": "date",
              "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||yyyy-MM||yyyy"
            }
          }
        }
      }
    },
    "aliases": {
      "all_products": {}
    }
  },
  "priority": 200,
  "version": 1,
}

如果我在评论文本中搜索任何特定术语,则响应会花费太多时间。

{
    "_source":{
        "excludes":["review"]
    },
    "size":1,
    "track_total_hits":true,
    "query":{
        "nested":{
            "path":"review",
            "query":{
                "match":{
                    "review.text":{
                        "query":"good",
                        "zero_terms_query":"none"
                    }
                }
            }
        }
    },
    "highlight":{
        "pre_tags":[
            "<b>"
        ],
        "post_tags":[
            "</b>"
        ],
        "fields":{
            "product_name":{
                
            }
        }
    }
}

我确定我遗漏了一些明显的东西。

【问题讨论】:

    标签: elasticsearch lucene elasticsearch-dsl elasticsearch-7 elasticsearch-nested


    【解决方案1】:

    简单的事情:track_total_hits 应该设置为 false。 强制合并的维护也可能有所帮助。

    第一次和下一次请求时间的差异是由于elasticsearch缓存。

    但是,如果我的理解力不错,您可以对文档进行超过 50k 条评论吗? 如果是对的,那就太多了。 你能想到反转你的映射吗? 具有将相关产品嵌入和对象的评论索引。它应该更快。

    PUT reviews 
    {
      "mappings": {
        "properties": {
          "text": {
            "type": "text"
          },
          "review_date": {
            "type": "date",
            "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||yyyy-MM||yyyy"
          },
          "product": {
            "properties": {
              "product_number": {
                "type": "text",
                "analyzer": "keyword"
              },
              "product_name": {
                "type": "text"
              },
              "first_fetch_date": {
                "type": "date",
                "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||yyyy-MM||yyyy"
              },
              "last_fetch_date": {
                "type": "date",
                "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||yyyy-MM||yyyy"
              }
            }
          }
        }
      }
    }
    

    【讨论】:

    • 感谢您的回复,但我需要获得匹配的总文档才能在我的网站上显示,这就是为什么我启用 track_total_hits 并且您建议的映射对我不起作用,我需要映射所有评论对于没有为每个评论映射产品的产品,在您的情况下,如果我搜索产品,如果我没有错,我会得到多个结果。
    • 你可以通过 2 个请求来完成。在评论索引中获取匹配的产品 id,然后在第一个索引上使用 ids 查询进行搜索。它应该更快。您还可以使用产品名称的聚合作为示例。如果您获得了几款产品,上面有超过 50k 条评论,并且想要“所有评论都映射到一个产品”,那么您的回复一定很重,不是吗?顺便说一句,您的来源不排除示例查询中的任何内容
    • 我已经更新了我的查询,不包括结果中的评论,正如我所提到的,我有 1.07 亿个文档(产品),在你的情况下,考虑我查询了一个术语并且匹配了来自一个产品的 10k 条评论,并且我想要所有与我给定术语的任何评论相匹配的产品,在你的情况下,我得到一个产品的 10k 结果,如果它匹配 1M 产品,我可能会得到多少结果集,我如何使用第一次查询和搜索中的所有 id其次,希望你明白我的意思。
    • 如果你添加一个大小 0 和一个术语 agg + top_hits 你会得到你所需要的。但是,如果您想获得返回 1M 产品的查询的所有结果,则必须分页。 (使用滚动查询或类似的东西)我能想到的用例很少,您需要所有结果。对于 UI,前 10 个或前 100 个就足够了。对于一批,最好使用卷轴。 107M的文件是不是丢了elastic。 (在您的情况下,拥有 2 或 3 个小节点可能比大节点更好)
    • 这可能有效,但我看到产品的冗余数据,如果我将评论索引和产品索引分开,我无法搜索产品详细信息和评论,如果我想这样做,我们需要有产品每个评论中的详细信息,我认为这不是一个好主意。我认为我们正朝着不同的方向前进。
    猜你喜欢
    • 1970-01-01
    • 2018-01-08
    • 2019-11-14
    • 2012-09-03
    • 2013-07-11
    • 2017-09-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多