返回顶部
首页 > 资讯 > 后端开发 > Python >SpringDataElasticsearch与SpEL表达式实现ES动态索引
  • 820
分享到

SpringDataElasticsearch与SpEL表达式实现ES动态索引

2024-04-02 19:04:59 820人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

目录前言实现动态获取索引类索引数据模型ES存储库实现测试注意前言 一般情况下,当我们使用 springDataelasticsearch 去操作 ES&

前言

一般情况下,当我们使用 springDataelasticsearch 去操作 ES 时,索引名称都会在 @Document 注解中写死,每次都是对这个固定的索引进行操作。

假如我们现在处于一个多租户系统中,每个租户都有自己所对应的用户数据,而这些用户数据都会被导入到 ES 中,那怎么实现各个租户的用户数据索引隔离呢?

换言之,在同一个索引结构的情况下怎么实现一个租户一个索引?

解决方案:使用 SpEL 表达式动态获取索引。

实现

动态获取索引类

DynamicIndex.java

package cn.xeblog.userprovider.es;

import cn.hutool.core.util.StrUtil;
import org.springframework.stereotype.Component;


@Component
public class DynamicIndex {

    private static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<>();

    
    public String getSuffix() {
        return THREAD_LOCAL.get();
    }

    
    public void setSuffix(String suffix) {
        THREAD_LOCAL.set(suffix);
    }

    
    public void remove() {
        THREAD_LOCAL.remove();
    }

    
    public String getIndex() {
        if (StrUtil.isBlank(getSuffix())) {
            return null;
        }

        return "user_" + getSuffix();
    }

}

原理:一般在请求后台接口的时候,我们会根据前端传过来的 Token ,解析出当前的用户信息,然后放置在当前请求线程的 ThreadLocal 中,当调用 getIndex() 方法时,会从当前线程的 ThreadLocal 中获取出用户的编号(索引后缀),然后拼接为一个完整的索引返回。

我这里为了方便测试,提供了 setSuffix()、remove() 等方法,用于手动设置或移除当前索引后缀。

索引数据模型

EsUserInfo.java

package cn.xeblog.userprovider.es.model;

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;


@Data
@Document(indexName = "#{@dynamicIndex.getIndex()}", type = "_doc", createIndex = false)
public class EsUserInfo {

    @Id
    private Long id;

    
    private String username;

    
    private String gender;

    
    private Integer age;

}

indexName 设置为 #{@dynamicIndex.getIndex()} ,这是一个 SpEL 表达式,dynamicIndex 就是我们上面创建的动态获取索引类的对象,当需要获取索引名称的时候,getIndex() 方法就会被调用。

createIndex 一定要设置为 false,避免当项目启动时索引被自动创建。

ES存储库实现

EsUserInfoRepository.java

无需定义任何方法

package cn.xeblog.userprovider.es;

import cn.xeblog.userprovider.es.model.EsUserInfo;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

public interface EsUserInfoRepository extends ElasticsearchRepository<EsUserInfo, Long> {

}

测试

package cn.xeblog.userprovider.es;

import cn.xeblog.userprovider.es.model.EsUserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class EsUserInfoRepositoryTest {

    @Resource
    private EsUserInfoRepository esUserInfoRepository;
    @Resource
    private DynamicIndex dynamicIndex;

    @Test
    public void addUserInfo() {
        EsUserInfo userInfo = new EsUserInfo();
        userInfo.setId(1L);
        userInfo.setUsername("张三");
        userInfo.setGender("男");
        userInfo.setAge(18);
        // 索引后缀为当前租户ID:10001
        dynamicIndex.setSuffix("10001");
        // 为租户10001添加用户
        esUserInfoRepository.save(userInfo);
        // 移除后缀
        dynamicIndex.remove();

        EsUserInfo userInfo2 = new EsUserInfo();
        userInfo2.setId(2L);
        userInfo2.setUsername("李四");
        userInfo2.setGender("男");
        userInfo2.setAge(21);
        // 索引后缀为当前租户ID:10002
        dynamicIndex.setSuffix("10002");
        // 为租户10002添加用户
        esUserInfoRepository.save(userInfo2);
        // 移除后缀
        dynamicIndex.remove();
    }

}

我这里分别为 租户10001 和 租户10002 各创建了一个用户。

注意

除了 createIndex 一定要设置为 false 之外,还有一个需要特别注意的地方:

DynamicIndex 的 getIndex() 方法在获取不到当前的索引后缀的情况下,一定要返回null !!!

    
    public String getIndex() {
        if (StrUtil.isBlank(getSuffix())) {
	    // 一定要返回null
            return null;
        }

        return "user_" + getSuffix();
    }

为什么呢?

浅看一下 ElasticsearchRepository.java 源码你就懂了。

AbstractElasticsearchRepository.java 是 ElasticsearchRepository.java 的具体实现类,我们看一下这个类的 save() 方法的实现代码

	@Override
	public <S extends T> S save(S entity) {

		Assert.notNull(entity, "Cannot save 'null' entity.");

		elasticsearchOperations.index(createIndexQuery(entity));
		elasticsearchOperations.refresh(entityInfORMation.getIndexName());

		return entity;
	}

当执行到 elasticsearchOperations.refresh(entityInformation.getIndexName()); 这行代码时,获取到的索引后缀可能为空。

原因在于 entityInformation.getIndexName()

MappingElasticsearchEntityInformation.java

	@Override
	public String getIndexName() {
		return indexName != null ? indexName : entityMetadata.getIndexName();
	}

在项目启动时,SpringDataElasticsearch 会去解析一次 @Document 注解获取出索引名称,并将索引名称保存到 MappingElasticsearchEntityInformation.java 类的 indexName 字段中,后续调用 entityInformation.getIndexName() 时,indexName 字段值不为 null 时会直接返回,不会再去解析 @Document 注解。

这样就存在一个问题,当项目启动的时候 getSuffix() 返回的肯定是 null,如果在 getIndex() 方法中去掉判空代码,第一次调用时,返回的索引名称肯定会是 user_null,这样就会出现索引不存在的问题。

到此这篇关于SpringDataElasticsearch与SpEL表达式实现ES动态索引的文章就介绍到这了,更多相关SpringDataElasticsearch实现ES动态索引内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: SpringDataElasticsearch与SpEL表达式实现ES动态索引

本文链接: https://lsjlt.com/news/167189.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • SpringDataElasticsearch与SpEL表达式实现ES动态索引
    目录前言实现动态获取索引类索引数据模型ES存储库实现测试注意前言 一般情况下,当我们使用 SpringDataElasticsearch 去操作 ES&...
    99+
    2024-04-02
  • es自动创建索引怎么实现
    在Elasticsearch中,可以通过以下几种方式自动创建索引: 动态映射(Dynamic Mapping):Elastics...
    99+
    2023-10-24
    es
  • Java 中执行动态表达式语句前中后缀Ognl、SpEL、Groovy、Jexl3
    目录Ognl、SpEL、Groovy、Jexl3一、前中后缀简单描述1、前缀、中缀、后缀表达式(逆波兰表达式)2、中缀表达式3、后缀表达式4、前缀表达式二、OGNL三、SpEL四、J...
    99+
    2024-04-02
  • java利用JEXL实现动态表达式编译
    背景 做项目突然遇到这样的需求: 系统要获取多个数据源的数据,并进行处理,最后输出多个字段。字段的计算规则一般是简单的取值最多加一点条件判断。 而且需要动态变动!!例如一个字段a的取...
    99+
    2024-04-02
  • Mybatis如何使用ognl表达式实现动态sql
    本文讲述在mybatis中如何使用ognl表达式实现动态组装sql语句 新建Users实体类: public class Users { private Integer ...
    99+
    2024-04-02
  • Mybatis怎么使用ognl表达式实现动态sql
    这篇文章主要为大家展示了“Mybatis怎么使用ognl表达式实现动态sql”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Mybatis怎么使用ognl表达式实现动态sql”这篇文章吧。新建Us...
    99+
    2023-06-15
  • java如何利用JEXL实现动态表达式编译
    小编给大家分享一下java如何利用JEXL实现动态表达式编译,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!背景做项目突然遇到这样的需求:系统要获取多个数据源的数据...
    99+
    2023-06-14
  • Python+eval函数实现动态地计算数学表达式详解
    目录Python 的 eval()第一个参数:expression第二个参数:globals第三个参数:locals用 eval() 计算表达式布尔表达式数学表达式通用表达式Pyth...
    99+
    2024-04-02
  • Python列表的索引与切片怎么实现
    今天小编给大家分享一下Python列表的索引与切片怎么实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。什么是索引?哪些数据...
    99+
    2023-06-29
  • vue实现动态表单动态渲染组件的方式(1)
    vue 实现动态表单/动态渲染组件的方式(一),供大家参考,具体内容如下 思路 先写好各个可能会出现的表单或者自定义的组件,引入。此时后端可能会给到一个对象型数组,每个对象有要渲染组...
    99+
    2024-04-02
  • vue实现动态表单动态渲染组件的方式(2)
    本文实例为大家分享了vue实现动态表单动态渲染组件的方式,供大家参考,具体内容如下 思路 先把所有可能出现的表单/组件写在主页面每个表单/组件的slot 属性值要与后端返回的表单/组...
    99+
    2024-04-02
  • C#中怎么利用正则表达式实现预搜索
    这篇文章将为大家详细讲解有关C#中怎么利用正则表达式实现预搜索,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。C#正则表达式之正向预搜索声明格式:正声明 “(=&hellip;)”,负...
    99+
    2023-06-17
  • lambda表达式与传统接口函数如何实现
    这篇文章主要讲解了“lambda表达式与传统接口函数如何实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“lambda表达式与传统接口函数如何实现”吧!一、接口定义首先,我们要明白lambd...
    99+
    2023-06-29
  • C#循环与循环控制的表达式树实现
    C# 提供了以下几种循环类型。 循环类型描述while 循环当给定条件为真时,重复语句或语句组。它会在执行循环主体之前测试条件。for/foreach 循环多次执行一个语句序列,简化...
    99+
    2024-04-02
  • C#使用第三方组件实现动态解析和求值字符串表达式
    目录介绍1、Z.Expressions.Eval 表达式解析2、NReco.LambdaParser 表达式解析3、DynamicExpresso 表达式解析4、SQL条件语句的正则...
    99+
    2024-04-02
  • PL/SQL中的分区表与分区索引怎么实现
    在 PL/SQL 中实现分区表和分区索引,可以通过以下步骤: 创建分区表:在创建表的时候,使用 PARTITION BY 子句指定...
    99+
    2024-05-08
    PL/SQL
  • 用 Go 实现一个完整的数学表达式计算引擎
    导读这篇文章将从头开始,使用 Go 语言来实现一个完整的数学表达式计算引擎。本文采用的是抽象语法树(Abstract Syntax Tree,AST)实现方式。虽然本文的实现代码为 Go,但不用纠结于此,语言只是实现方式的一种选择,作为开发...
    99+
    2024-04-02
  • VBS中正则表达式如何实现选择与编组
    这篇文章给大家分享的是有关VBS中正则表达式如何实现选择与编组的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。选择与编组选择允许使用 '|' 字符来在两个或多个候选项中进行选择。通过扩展章节标题的正...
    99+
    2023-06-09
  • Spring Security实现基于RBAC的权限表达式动态访问控制的操作方法
    目录资源权限表达式Spring Security中的实现MethodSecurityExpressionHandler思路以及实现配置和使用昨天有个粉丝加了我,问我如何实现类似shi...
    99+
    2024-04-02
  • RiSearch PHP 实现动态筛选与聚合搜索的技巧
    引言:随着互联网的发展和数据规模的增加,搜索引擎的功能需求也越来越多样化。用户不再满足于简单的关键字搜索,而是希望能够根据自己的需求进行筛选和聚合搜索。RiSearch 是一个基于 PHP 的高性能全文搜索引擎,可以满足动态筛选和聚合搜索的...
    99+
    2023-10-21
    PHP (编程语言) RiSearch (实时搜索引擎) 动态筛选与聚合搜索
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作