Elasticsearch因其灵活性而被广泛用于构建定制化的搜索解决方案。然而,这种灵活性也意味着如果不小心,可能会犯错误。无论是刚开始还是在调整现有设置,提前实施智能策略可以节省大量时间和麻烦。
本文将介绍三个关键技巧:数据预处理(即“数据按摩”)、数据增强和选择正确的字段类型,帮助你立即提升搜索系统的性能并避免常见的陷阱。
为了实际运用这些技巧,让我们考虑一个常见的用例:社交媒体分析平台。在这个案例中,每个文档包含一个帖子的相关数据。以下是数据定义。
索引映射: 该映射包含所有需要遵循本博客中建议的字段定义。
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"
}
“数据按摩”指的是在搜索之前对数据进行预处理。这样做的原因包括:
将字符串列表转换为实际数组可以正确过滤或聚合文档。例如,假设我们有一个这样的关键词字段:
{
"hashtags_string": "#elastic,#kibana,#ingest_tips"
}
使用这种字段,我们无法单独过滤每个标签,必须完全匹配整个字符串。因此,下面的查询无法找到文档:
GET post-performance-metrics/_search
{
"query": {
"term": {
"hashtags_string": {
"value": "#ingest_tips"
}
}
}
}
但如果我们将标签拆分,将字段转换为以下格式:
{
"hashtags_string": [
"#elastic",
"#kibana",
"#ingest_tips"
]
}
查询就可以成功找到文档,因为存在一个精确匹配的标签#ingest_tips
!
我们可以在一个数据处理管道中定义分割处理器,如下:
PUT _ingest/pipeline/hashtag_splitter
{
"description": "Splits hashtag string into array",
"processors": [
{
"split": {
"field": "hashtags_string",
"separator": ",",
"target_field": "hashtags_string"
}
}
]
}
注意,我们可以为源字段(field参数)和结果字段(target_field参数)定义不同的字段,也可以定义任何字符(或模式)来分割字符串。可以将此管道定义为索引的默认管道,以便任何索引的文档都会经过此管道处理,使数据立即可用。
其他运行管道的选项包括更新查询请求或重新索引操作,指定使用的管道。
在分析数据集以计算指标时,一些常见操作会反复出现。例如,要计算总参与度,我们需要加上点赞数、评论数和分享数。我们可以每次查询时进行计算(每次搜索时),或者仅在索引文档时计算一次(预计算)。后一种方式通过减少查询时间显著提高性能。
为此,我们可以定义一个脚本处理器来执行操作并在数据处理过程中设置总值。这样,我们最终得到一个如下的文档:
{
"total_engagements": 20,
"likes": 12,
"comments": 6,
"shares": 2
}
我们可以再次定义一个处理管道,如下所示:
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
}
}
}
}
现在,让我们在一个脚本处理器中定义三个粉丝等级:
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"
}
}
]
}
现在我们的文档有了一个新的关键词字段follower_tier
,其值是预计算的粉丝等级:
{
"follower_count": 25600,
"follower_tier": "medium"
}
我们可以使用一个更快且更易于使用的词条查询来过滤这些创作者:
GET post-performance-metrics/_search
{
"query": {
"term": {
"follower_tier": {
"value": "medium"
}
}
}
}
词条查询通常比范围查询快,因为它们涉及直接查找。通过将范围转换为单个字段,我们可以利用这种速度优势。
数据增强意味着使用外部来源来扩展索引中的数据,为索引文档增加上下文和深度。
增强管道在数据处理过程中通过使用来自另一个索引的数据来增强一个索引中的文档。这种方法简化了数据管理,因为它集中存储了附加信息,比如从专用来源丰富多个索引,允许对增强数据进行一致的查询。
在我们的示例中,我们将使用来自不同索引的创作者人口统计数据来丰富帖子。
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. 创建并执行一个增强策略:增强策略定义数据如何与我们想要丰富的文档相关联。
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
现在,我们将创建一个使用此策略的数据处理管道:
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"
}
推理管道允许我们使用部署在Elasticsearch集群中的机器学习(ML)模型,根据文档生成推断数据。在我们的示例中,我们将使用Elasticsearch中自带的lang_ident_model_1
模型,它用于从文本中识别语言。
1. 创建一个包含推理处理器的数据处理管道以使用模型:
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. 将管道应用于我们的数据。
原始文档:
{
"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"
}
}
在这里,模型正确地将内容识别为西班牙语!
总的来说,这个功能值得探索,因为它支持非常有趣的用例,例如:
如果你需要使用不同的模型,请查看Elastic的Eland;它与HuggingFace兼容性很好!
提示: 记住,你可以在同一个处理管道中定义多个处理器,它们不一定需要相关。因此,我们在这里创建的所有示例都可以在一个管道中使用!
选择正确的字段类型常常被忽视,但它可以对性能和功能产生重大影响。Elasticsearch提供了超过40种字段数据类型,每种都有其自身的优势。许多类型纯粹是基于性能的,比如根据值的长度选择数字类型,而其他类型则提供额外的封装功能。你知道吗:
还有更多!你可以查看文档。
在本文中,我们将使用帖子的点赞数来提升它在搜索结果中的排名。为此,我们可以定义一个rank_feature
类型字段并运行一个rank_feature
查询。这将为我们的查询增加一个非常有用的功能,其对性能的影响远小于函数分数查询。
1. 定义正确的映射:因为我们可能希望在其他查询中使用点赞数,因此我们将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```json
time in half with Elasticsearch optimization",
"likes": 1200
}
},
{
"_score": 1.2482762,
"_source": {
"content": "Just upgraded our Elasticsearch deployment and the speed difference is unbelievable!",
"likes": 78
}
}
]
}
}
相关性是主观的!它取决于你的用户是谁,他们在搜索什么,他们如何搜索,你的数据是什么,你的业务需求是什么等等。 了解更多关于相关性的信息。
这里的想法是拥有更复杂的查询,这些查询也会影响整体排名,而rank_feature
查询在该排名的基础上工作,从而产生更好的结果。
本文探讨了优化Elasticsearch的三个关键技巧:数据预处理(字段处理)、使用外部来源丰富数据以及选择适当的字段类型。
这些技巧适用于不同的用例,并为你开发自己的数据处理管道、简化现代NLP技术以创建新功能以及在使用Elasticsearch时应用最佳实践铺平了道路。
通过应用这些技巧,你可以构建更强大且高效的搜索系统,使查询和索引更容易和更易于维护。尝试在自己的Elasticsearch部署中实施这些技巧,看看效果如何。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。