美文网首页
如何优化因为高亮造成的大文本(大字段)检索缓慢问题

如何优化因为高亮造成的大文本(大字段)检索缓慢问题

作者: 醉鱼java | 来源:发表于2023-08-22 08:04 被阅读0次

    首先还是说一下背景,工作中用到了 elasticsearch 的检索以及高亮展示,但是索引中的content字段是读取的大文本内容,所以后果就是索引的单个字段很大,造成单独检索请求的时候速度还可以,但是加入高亮之后检索请求的耗时就非常的慢了。所以本文从更换高亮器类型的角度来解决因为高亮造成的检索请求缓慢的问题。

    ES的抵消策略

    在文章开始前先简单介绍一个elasticsearch的策略,为了在检索的字段中创建出一个有意义的高亮片段,高亮器会使用原始文本的开始和结束字符串的偏移量,偏移量的获取可以从一下方式获得

    • postings list:如果在mappingindex_options设置为offsetsunified高亮器使用此信息高亮显示文档而不用再次分析文本。
    • term vectors:如果我们在mapping中设置term_vectorwith_positions_offsets,则unified高亮器会自动使用term_vector来高亮显示,对于大于1M的大字段,使用term_vector速度会很快,fvh高亮器就是使用的term_vector
    • plain highlighting:当unified没有其他的选择的时候会使用plain模式,它会创建了一个微小的内存索引,并通过Lucene的查询执行计划器重新运行原始查询条件。plain高亮器默认使用的就是此模式

    大文本的纯高亮展示可能需要大量的时间和内存,为了防止这种情况,es默认将大文本的字符数量限制为1000000,可以使用index.highlight.max_analyzed_offset修改此默认设置

    一、FVH高亮器简介

    FVH(Fast Vector Highlighter)是Elasticsearch高亮器中的一种算法,使用的是Lucene Fast Vector highlighter,它能够快速而准确地在文本中找到匹配的关键词,并将其标记为高亮。相比于其他高亮器算法,FVH在性能上有着显著的优势,特别适用于大规模数据集和高并发的场景。

    二、FVH高亮器的使用方法

    安装

    首先,确保已经正确安装了 Elasticsearch

    version: '3.8'
    services:
      cerebro:
        image: lmenezes/cerebro:0.8.3
        container_name: cerebro
        ports:
         - "9000:9000"
        command:
         - -Dhosts.0.host=http://eshot:9200
        networks:
         - elastic
      kibana:
        image: docker.elastic.co/kibana/kibana:8.1.3
        container_name: kibana
        environment:
          - I18N_LOCALE=zh-CN
          - XPACK_GRAPH_ENABLED=true
          - TIMELION_ENABLED=true
          - XPACK_MONITORING_COLLECTION_ENABLED="true"
          - ELASTICSEARCH_HOSTS=http://eshot:9200
          - server.publicBaseUrl=http://192.168.160.234:5601
        ports:
          - "5601:5601"
        networks:
          - elastic
      eshot:
        image: elasticsearch:8.1.3
        container_name: eshot
        environment:
          - node.name=eshot
          - cluster.name=es-docker-cluster
          - discovery.seed_hosts=eshot,eswarm,escold
          - cluster.initial_master_nodes=eshot,eswarm,escold
          - bootstrap.memory_lock=true
          - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
          - xpack.security.enabled=false
          - node.attr.node_type=hot
        ulimits:
          memlock:
            soft: -1
            hard: -1
        volumes:
          - D:\zuiyuftp\docker\es8.1\eshot\data:/usr/share/elasticsearch/data
          - D:\zuiyuftp\docker\es8.1\eshot\logs:/usr/share/elasticsearch/logs
          - D:\zuiyuftp\docker\es8.1\eshot\plugins:/usr/share/elasticsearch/plugins
        ports:
          - 9200:9200
        networks:
          - elastic
      eswarm:
        image: elasticsearch:8.1.3
        container_name: eswarm
        environment:
          - node.name=eswarm
          - cluster.name=es-docker-cluster
          - discovery.seed_hosts=eshot,eswarm,escold
          - cluster.initial_master_nodes=eshot,eswarm,escold
          - bootstrap.memory_lock=true
          - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
          - xpack.security.enabled=false
          - node.attr.node_type=warm
        ulimits:
          memlock:
            soft: -1
            hard: -1
        volumes:
          - D:\zuiyuftp\docker\es8.1\eswarm\data:/usr/share/elasticsearch/data
          - D:\zuiyuftp\docker\es8.1\eswarm\logs:/usr/share/elasticsearch/logs
          - D:\zuiyuftp\docker\es8.1\eshot\plugins:/usr/share/elasticsearch/plugins
        networks:
          - elastic
      escold:
        image: elasticsearch:8.1.3
        container_name: escold
        environment:
          - node.name=escold
          - cluster.name=es-docker-cluster
          - discovery.seed_hosts=eshot,eswarm,escold
          - cluster.initial_master_nodes=eshot,eswarm,escold
          - bootstrap.memory_lock=true
          - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
          - xpack.security.enabled=false
          - node.attr.node_type=cold
        ulimits:
          memlock:
            soft: -1
            hard: -1
        volumes:
          - D:\zuiyuftp\docker\es8.1\escold\data:/usr/share/elasticsearch/data
          - D:\zuiyuftp\docker\es8.1\escold\logs:/usr/share/elasticsearch/logs
          - D:\zuiyuftp\docker\es8.1\eshot\plugins:/usr/share/elasticsearch/plugins
        networks:
          - elastic
    
    # volumes:
    #   eshotdata:
    #     driver: local
    #   eswarmdata:
    #     driver: local
    #   escolddata:
    #     driver: local
    
    networks:
      elastic:
        driver: bridge
    

    创建索引

    在使用FVH高亮器之前,需要先创建一个索引,并将需要高亮的字段进行映射。例如,我们要在content字段中进行高亮,可以使用以下代码:

    PUT /example_target
    {
      "mappings": {
        "properties": {
          "content": {
            "type": "text",
            "analyzer": "ik_max_word",
            "term_vector": "with_positions_offsets"
          },
          "title": {
            "type": "text",
            "analyzer": "ik_max_word",
            "term_vector": "with_positions_offsets"
          }
        }
      }
    }
    

    添加测试数据

    POST example_target/_doc
    {
      "content":"中华人民共和国是否考虑是否就爱上速度加快分解ask计算机卡死撒中华上的飞机拉丝机是的地方记录 卡就是开发建设看积分卡说了句 ask就疯狂萨拉丁就发士大 sdf 看得见啊李开复 圣诞节卡了 夫哈数据库中华啊,中华,人民爱上中华",
      "title":"中华人名共和国"
    }
    

    查询并高亮

    使用FVH高亮器进行查询和高亮的过程如下所示:

    GET example_target/_search
    {
      "query": {
        "match": {
          "content": "中华 爱上"
        }
      },
      "highlight": {
        "pre_tags": "<em>",
        "post_tags": "</em>", 
        "require_field_match": "false", 
        "fields": {
          "content": {
             "type": "fvh",
            "fragment_size": 18,
            "number_of_fragments": 3
          }
        }
      }
    }
    

    以上代码中,我们通过match查询找到了包含关键词的文档,然后在highlight内容中指定了需要高亮的字段,这里是content。执行述查询后,Elasticsearch将返回匹配的结果,并在content字段中添加了高亮标记。

    数据量少的时候对比不是特别明显,所以在测试时,可以在索引中添加大量的测试数据进行测试,本人在测试过程中es的索引大小在500M左右,单个字段纯文本大小也有1-2M。此时这种数据规模下使用普通的高亮器在检索请求时就已经非常缓慢了,根据返回的数据量多少来决定,在取10条数据时已经能达到6秒了,但是在使用fvh高亮器之后时间已经进入毫秒级

    三、FVH高亮器的参数配置

    先看一下返回的数据结果在对照下面参数学习

    {
      "took" : 4,
      "timed_out" : false,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 3,
          "relation" : "eq"
        },
        "max_score" : 0.41193593,
        "hits" : [
          {
            "_index" : "example_target",
            "_id" : "f1rkC4oBCDmhQc2yo6PQ",
            "_score" : 0.41193593,
            "_source" : {
              "content" : "中华人民共和国是否考虑是否就爱上速度加快分解ask计算机卡死撒中华上的飞机拉丝机是的地方记录 卡就是开发建设看积分卡说了句 ask就疯狂萨拉丁就发士大 sdf 看得见啊李开复 圣诞节卡了 夫哈数据库中华啊,中华,人民爱上中华"
            },
            "highlight" : {
              "content" : [
                "<em>中华</em>人民共和国是否考虑是否就<em>爱上</em>速度",
                "sk计算机卡死撒<em>中华</em>上的飞机拉丝机是的地方记录",
                "夫哈数据库<em>中华</em>啊,<em>中华</em>,人民<em>爱上</em>中华"
              ]
            }
          },
          {
            "_index" : "example_target",
            "_id" : "G3Fi44kB4IVEhjafHXOf",
            "_score" : 0.33311102,
            "_source" : {
              "content" : "中华人民共和国是否考虑是否就爱上速度加快分解ask计算机卡死撒中华上的飞机拉丝机是的地方记录卡就是开发建设看积分卡说了句ask就疯狂萨拉丁就发士大夫哈数据库"
            },
            "highlight" : {
              "content" : [
                "<em>中华</em>人民共和国是否考虑是否就<em>爱上</em>速度",
                "sk计算机卡死撒<em>中华</em>上的飞机拉丝机是"
              ]
            }
          },
          {
            "_index" : "example_target",
            "_id" : "HHFt44kB4IVEhjafE3Ov",
            "_score" : 0.31932122,
            "_source" : {
              "content" : "中华人民共和国是否考虑是否就爱上速度加快分解ask计算机卡死撒中华上的飞机拉丝机是的地方记录 卡就是开发建设看积分卡说了句 ask就疯狂萨拉丁就发士大 sdf 看得见啊李开复 圣诞节卡了 夫哈数据库"
            },
            "highlight" : {
              "content" : [
                "<em>中华</em>人民共和国是否考虑是否就<em>爱上</em>速度",
                "sk计算机卡死撒<em>中华</em>上的飞机拉丝机是的地方记录"
              ]
            }
          }
        ]
      }
    }
    
    

    通过上面的查询请求中高亮参数的指定可以发现,高亮器还是支持其他的参数的,那么我们下面将对几个常用的参数进行说明

    • fragment_size:指定每个高亮片段的长度,默认为100个字符。

    • number_of_fragments:指定返回的高亮片段数量,默认为5个。

    • pre_tagspost_tags:分别指定高亮标记的前缀和后缀,默认为<em></em>

    • require_field_match:指定是否要求所有字段都匹配关键词才进行高亮,默认为true。可以开启关闭此参数对上面的title字段进行校验

    • type:指定fvh高亮器,除了fvh之外还有unifiedplain

      • unified 是默认的高亮器,可以将文本分解为句子,并使用BM25算法对单个句子进行评分,还支持精确的短语高亮显示,支持(fuzzyprefixregex)高亮。
      • plain 普通的高亮器,适用与简单的查询或者单个字段的匹配。为了准确的反应查询逻辑,它会在内存中创建一个很小的索引,来对原始的查询语句进行执行,来访问当前更低级别的匹配信息。

    在使用FVH高亮器时,根据实际需求,可以灵活地调整这些参数,以获得最佳的高亮效果。

    总结

    通过本文的介绍,我们了解了Elasticsearch高亮器中的FVH算法,并学会了如何使用它为搜索结果增添亮点。FVH高亮器在性能和功能上都有着明显的优势,对于大规模数据集和高并发的场景尤为适用。希望读者通过本文的指引,能够更好地利用FVH高亮器来提升搜索结果的可读性和用户体验。

    参考链接

    https://www.elastic.co/guide/en/elasticsearch/reference/8.1/highlighting.html

    如果感觉本文对你有所帮助欢迎点赞评论转发收藏。如果你想了解更多关于ES的骚操作,更多实战经验,点击查看原文

    原文链接
    https://mp.weixin.qq.com/s?__biz=MzIwNzYzODIxMw==&mid=2247486065&idx=1&sn=28ee03fd0e297eb0c5d62405446d4551&chksm=970e11dba07998cd53a3a16e39e396172c3e3b46f96bab0e097eeab08fefb93c63b0d48fe380#rd

    相关文章

      网友评论

          本文标题:如何优化因为高亮造成的大文本(大字段)检索缓慢问题

          本文链接:https://www.haomeiwen.com/subject/jczymdtx.html