3 个数据摄取技巧,彻底改变你的搜索方式

作者:来自 Elastic Alexander Dávila

通过以下技巧,将你的 Elasticsearch 数据摄取提升到新水平:数据预处理、数据增强,以及选择正确的字段类型。

了解将数据摄取到 Elasticsearch 的多种方式,并通过实用示例尝试一些新方法。

Elasticsearch 拥有丰富的新功能,帮助你为你的使用场景构建最佳的搜索解决方案。现在就开始免费试用吧。


Elasticsearch 的灵活性非常适合构建定制化的搜索方案。但正因为它的灵活性,如果不小心,也很容易出错。无论你是刚开始搭建,还是在优化现有设置,及早实施一些聪明的策略,都能为你节省大量时间和麻烦。

在这篇文章中,我们将介绍 3 个关键技巧:数据预处理(也叫“数据清洗”)、数据增强,以及选择正确的字段类型,帮助你立刻提升搜索系统的性能,并避免常见陷阱。

实用用例设置

为了看到这些技巧的实际效果,让我们来看一个常见的用例:一个社交媒体分析平台。在这个场景中,每个文档都包含一条帖子的相关数据。数据定义如下。

索引映射:这个映射包含了应用本文所提技巧所需的所有字段定义。

PUT post-performance-metrics
{
  "mappings": {
    "properties": {
      "hashtags_string": {
        "type": "keyword"
      },
      "total_engagements": {
        "type": "integer"
      },
      "likes": {
        "type": "integer",
        "fields": {
          "ranking": {
            "type": "rank_feature"
          }
        }
      },
      "comments": {
        "type": "integer"
      },
      "shares": {
        "type": "integer"
      },
      "follower_count": {
        "type": "long"
      },
      "follower_tier": {
        "type": "keyword"
      },
      "user_id": {
        "type": "keyword"
      },
      "content": {
        "type": "text"
      }
    }
  }
}

示例文档:这是文档最初的样子。

POST post-performance-metrics/_doc
{
    "user_id": "user123",
    "hashtags_string": "#elastic,#kibana,#ingest_tips",
    "likes": 12,
    "comments": 6,
    "shares": 2,
    "follower_count": 2560,
    "content": "Just learned more tips to improve my elastic game! #elastic #kibana #ingest_tips"
}

技巧

整理字段 - massage fiels

“整理” 字段指的是对数据进行预处理,以便更好地支持搜索。这样做的原因包括:

  • 增强功能(例如:搜索数组)

  • 性能提升(例如:预计算字段)

将字符串列表转换为真正的数组

将字符串列表转换为真正的数组,可以让我们更准确地过滤或聚合文档;例如,假设我们有一个文档包含以下 keyword 字段:

{
    "hashtags_string": "#elastic,#kibana,#ingest_tips"
}

使用这种类型的字段,我们无法单独过滤每个 hashtag;必须完全匹配整个字符串。因此,下面这个查询将无法返回该文档:

GET post-performance-metrics/_search
{
    "query": {
        "term": {
            "hashtags_string": {
                "value": "#ingest_tips"
            }
        }
    }
}

另一方面,如果我们将 hashtags 拆分,使字段变成这样:

{
    "hashtags_string": [
        "#elastic",
        "#kibana",
        "#ingest_tips"
    ]
}

该查询实际上可以返回文档,因为存在一个精确匹配的词项 #ingest_tips!

我们可以在一个 ingest pipeline 中这样定义 split 处理器:

PUT _ingest/pipeline/hashtag_splitter
{
    "description": "Splits hashtag string into array",
    "processors": [
        {
            "split": {
                "field": "hashtags_string",
                "separator": ",",
                "target_field": "hashtags_string"
            }
        }
    ]
}

注意,我们可以为源字段(field 参数)和目标字段(target_field 参数)定义不同的字段名。我们也可以定义任意字符(或模式)来拆分字符串。

要使用这个 pipeline,可以将它定义为索引的默认 pipeline。这样,任何被索引的文档都会经过这个 pipeline,数据会立即准备好使用。

运行该 pipeline 的其他方式包括使用 _update_by_query 请求,或通过 reindex 操作指定要使用的 pipeline。

预计算字段

在分析数据集计算指标时,一些常见操作会反复出现。例如,计算总互动数时,我们需要将 likes + comments + shares 相加。我们可以每次查询时计算,或者只在索引文档时计算一次(预计算)。后一种方式通过减少查询时间,显著提升性能。

为此,我们可以定义一个脚本处理器,在摄取过程中执行该操作,并设置总值。这样,最终得到的文档会是这样的:

{ 
 "total_engagements": 20,
 "likes": 12,
 "comments": 6,
 "shares": 2
}

我们同样可以这样定义一个 ingest pipeline:

PUT _ingest/pipeline/engagement_calculator
{
    "description": "Calculates total engagement",
    "processors": [
        {
            "script": {
                "source": """
                    int likes = ctx.likes != null ? ctx.likes : 0;
                    int shares = ctx.shares != null ? ctx.shares : 0;
                    int comments = ctx.comments != null ? ctx.comments : 0;
                    ctx.total_engagements = likes + shares + comments;
                """
            }
        }
    ]
}

我们还添加了一个 if 参数,以确保所有相关字段都存在。

将范围预计算为单个字段

为了加快搜索速度,我们可以基于现有数据计算分类字段。在示例中,我们将创建一个 follower_tier 字段,根据作者的粉丝数量对帖子发布者进行分类。

在计算新的分类字段之前,先看一下查询。我们想获取中等规模创作者的帖子,这里定义为粉丝数在 10001 到 100000 之间。

为此,我们可以使用范围查询。但每次使用该过滤条件时,都要记住定义,且范围查询比精确匹配查询更慢。

GET post-performance-metrics/_search
{
    "query": {
        "range": {
            "follower_count": {
                "gte": 10001,
                "lte": 100000
            }
        }
    }
}

现在,让我们在脚本处理器中定义 3 个 follower tier:

PUT _ingest/pipeline/follower_tier_calculator
{
    "description": "Assigns influencer tier based on follower count",
    "processors": [
        {
            "script": {
                "source": """
         if (ctx.follower_count < 10000) {
           ctx.follower_tier = "small";
                } else if (ctx.follower_count < 100001) {
           ctx.follower_tier = "medium";
                } else {
           ctx.follower_tier = "large";
                }
       ""","if": "ctx.follower_count != null"
            }
        }
    ]
}

现在我们的文档有了一个新的 keyword 字段,叫 follower_tier,里面存着预计算好的 follower_tier 分类:

{
    "follower_count": 25600,
    "follower_tier": "medium"
}

这样我们就可以使用更快、更易用的 term 查询来过滤这些创作者:

GET post-performance-metrics/_search
{
    "query": {
        "term": {
            "follower_tier": {
                "value": "medium"
            }
        }
    }
}

term 查询通常比范围查询更快,因为它们是直接查找。通过将范围转换为单个字段,我们可以利用这种速度优势。

丰富数据

数据增强指的是使用外部来源扩展索引中的数据,给索引文档增加上下文和深度。

Enrich pipeline

Enrich pipeline 在摄取时利用另一个索引的数据来增强当前索引的文档。这简化了数据管理,通过集中额外信息(比如用专门来源增强多个索引),使对增强数据的查询更加一致。

在我们的示例中,我们将用来自不同索引的创作者人口统计数据来增强帖子。

1. 创建一个 user_demographics 索引,里面有如下数据

POST /user_demographics/_doc
{
    "user_id": "user123",
    "age_group": "25-34",
    "interests": [
        "technology",
        "fashion",
        "travel"
    ],
    "account_creation_date": "2022-01-15",
    "user_segment": "tech_enthusiast"
}

2. 创建并执行一个 enrich 策略:enrich 策略定义了数据与我们要增强的文档之间的关联方式。

PUT /_enrich/policy/user_demographics_policy
{
    "match": {
        "indices": "user_demographics",
        "match_field": "user_id",
        "enrich_fields": [
            "age_group",
            "interests",
            "account_creation_date",
            "user_segment"
        ]
    }
}

在这个例子中,我们将帖子索引的 user_id 与人口统计索引匹配,用来增强新进来的文档,添加所有其他字段。

执行该策略时,我们运行:

POST /_enrich/policy/user_demographics_policy/_execute

现在,我们将创建一个使用该策略的 ingest pipeline:

PUT /_ingest/pipeline/enrich_posts_with_user_data
{
    "description": "Enriches posts with user demographic data",
    "processors": [
        {
            "enrich": {
                "policy_name": "user_demographics_policy",
                "field": "user_id",
                "target_field": "user_demographics",
                "max_matches": 1
            }
        }
    ]
}

3. 测试新的策略。我们可以看到,任何带有匹配 user_id 的新帖子文档都会被增强,添加人口统计数据。

原始文档:

{
    "user_id": "user123"
} 

增强后的结果:

{
    "user_demographics": {
        "account_creation_date": "2022-01-15",
        "user_id": "user123",
        "age_group": "25-34",
        "user_segment": "tech_enthusiast",
        "interests": [
            "technology",
            "fashion",
            "travel"
        ]
    },
    "user_id": "user123"
}

推理 pipeline

推理 pipeline 让我们可以使用部署在 Elasticsearch 集群中 ML 节点上的机器学习(ML)模型,根据文档生成推断数据。在示例中,我们将使用 Elasticsearch 自带的 lang_ident_model_1 模型,它用于从文本中识别语言。

1. 创建一个包含推理处理器的 ingest pipeline 来使用该模型

PUT /_ingest/pipeline/detect_language
{
    "description": "Detects language of post content",
    "processors": [
        {
            "inference": {
                "model_id": "lang_ident_model_1",
                "target_field": "post_language",
                "field_map": {
                    "content": "text"
                }
            }
        }
    ]
}

注意我们如何定义目标字段(结果存储位置)和字段映射中的源字段(content)。

2. 将 pipeline 应用于我们的数据。

原始文档:

{
  "content": "Just learned more tips to improve my elastic game! "
}

查看带有推断字段的结果:

{
    "content": "Just learned more tips to improve my elastic game! ",
    "post_language": {
        "prediction_score": 0.9993826906956544,
        "model_id": "lang_ident_model_1",
        "prediction_probability": 0.9993826906956544,
        "predicted_value": "en"
    }
}

我们的结果(en)存储在 post_language.predicted_value。

让我们再试一个例子!

原始文档:

{
    "content": "Kibana me permitió crear las visualizaciones en minutos"
}

带有推断字段的结果:

{
    "content": "Kibana me permitió crear las visualizaciones en minutos",
    "post_language": {
        "prediction_score": 0.9823283879653826,
        "model_id": "lang_ident_model_1",
        "prediction_probability": 0.9823283879653826,
        "predicted_value": "es"
    }
}

这里,模型正确地将文本分类为西班牙语(Spanish)!

总体来说,这个功能值得探索,因为它支持很多有趣的用例,比如:

如果你需要使用不同的模型,可以看看 Elastic 的 Eland,它与 HuggingFace 配合得很好!

额外提示:记住,你可以在同一个 ingest pipeline 中定义多个处理器,这些处理器不一定要相关。所以我们这里所有的示例都可以放在一个 pipeline 里一起使用!

选择正确的字段类型

选择合适的字段类型常被忽视,但它对性能和功能有很大影响。Elasticsearch 提供了 40 多种字段类型,每种都有自己的优势。有些主要是性能优化,比如根据值的长度选择数字类型;有些则提供额外封装的功能。你知道吗:

还有更多!你可以查看官方文档了解详情。

rank_feature 示例

本文中,我们用帖子的 likes 数量来提升其在搜索结果中的排名。为此,我们可以定义一个 rank_feature 类型字段,并运行 rank_feature 查询。这会为查询增加一个非常有用的功能,同时对性能的影响远小于 function score 查询。

1. 定义正确的映射:因为我们可能想在其他查询中使用 likes 计数,所以将 rank_feature 定义为一个名为 “ranking” 的多字段。

PUT post-performance-metrics
{
    "mappings": {
        "properties": {
            "content": {
                "type": "text"
            },
            "likes": {
                "type": "integer",
                "fields": {
                    "ranking": {
                        "type": "rank_feature"
                    }
                }
            }
        }
    }
}

这里只展示了相关的映射部分。

2 . 索引包含 “likes” 字段的文档:记住,我们的映射定义已经负责填充所有多字段,所以我们只需要定义主字段 likes 即可。

POST post-performance-metrics/_doc
{
 "content": "Just upgraded our Elasticsearch deployment and the speed difference is noticeable.",
 "likes": 78
}

POST post-performance-metrics/_doc
{
 "content": "How we cut our search response time in half with Elasticsearch optimization",
 "likes": 1200
}

3. 运行 rank_feature 查询:通常会放在 should 子句中,只影响评分,不影响返回的文档结果。

GET post-performance-metrics/_search
{
    "query": {
        "bool": {
            "must": {
                "match": {
                    "content": "elasticsearch speed"
                }
            },
            "should": [
                {
                    "rank_feature": {
                        "field": "likes.ranking",
                        "boost": 1.5
                    }
                }
            ]
        }
    }
}

这里的期望是点赞更多的帖子会获得额外加分,这样即使查询更匹配其他帖子,也能优先显示更受欢迎的帖子。注意,我们可以控制点赞数对评分的影响程度;如果将 boost 设置低于 1.0,评分甚至会受到负面影响:

{
    "hits": {
        "hits": [
            {
                "_score": 1.3652647,
                "_source": {
                    "content": "How we cut our search response time in half with Elasticsearch optimization",
                    "likes": 1200
                }
            },
            {
                "_score": 1.2482762,
                "_source": {
                    "content": "Just upgraded Elasticsearch deployment and the speed difference is unbelievable!",
                    "likes": 78
                }
            }
        ]
    }
}

相关性是主观的!它取决于你的用户是谁,他们在搜索什么,怎么搜索,你的数据是什么,业务需求是什么,等等。了解更多关于相关性的信息

这里的想法是构建更复杂的查询,同时对整体排名产生影响,而 rank_feature 查询作用于该排名,以获得更好的结果。

总结

本文介绍了优化 Elasticsearch 的三个关键技巧:预处理数据(整理字段)、用外部来源增强数据,以及选择合适的字段类型。

这些技巧适用于不同的用例,帮助你开发自己的 ingest pipeline,简化现代 NLP 技术以创建新特性,并在使用 Elasticsearch 时应用最佳实践。

通过应用这些技巧,你可以构建更稳健、高效的搜索系统,使查询和索引更简单、更易维护。试着在你的 Elasticsearch 部署中实现这些技巧,体验不同。

原文:3 ingestion tips to change your search game forever - Elasticsearch Labs

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值