使用 Spring Data 查询 Redis 中的嵌套对象 [英] Query Nested Objects in Redis using Spring Data

查看:59
本文介绍了使用 Spring Data 查询 Redis 中的嵌套对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个如下的 java 对象,我存储在 redis 存储中.

I have a java object as below that i store in a redis store.

@RedisHash("UserProfile")
public class UserProfile implements Serializable {
    @Id String id;
    @Reference PersonalInfo personalInfo = new PersonalInfo();
    @Reference BusinessInfo businessInfo = new BusinessInfo();
    ...
}

现在,PersonalInfo 对象的结构如下:

Now, the PersonalInfo object is structured as:

public class PersonalInfo {
    private String firstName;
    private String lastName;
    @Indexed private String userId;
    private ContactInfo contactInfo = new ContactInfo();
}

请注意,PersonalInfo 对象中的 userId 已编入索引.

Note that userId in the PersonalInfo object is indexed.

我的目标是使用 spring 数据通过用户 ID 查询 redis 中的 UserProfile 对象.

My goal is to query the UserProfile objects in redis by their userIds, using spring data.

CrudRepository 接口将无法直接执行 findByUserId(),除非我在 UserProfile 对象中有 userId.我不想直接在 UserProfile 对象中使用 userId,如果有更好的方法来编写查询以通过 userid 查找用户.

The CrudRepository interface will not be able to directly do a findByUserId(), unless i have userId in the UserProfile object. I dont want to have the userId directly within the UserProfile object, if there is some better way to write a query to find users by userid.

关于我如何去做这件事有什么建议吗?

Any suggestion on how i can go about doing this?

更新:我将如下方法添加到存储库中:

Update: I added the method as below to the repository:

public interface UserProfileRepository extends CrudRepository<UserProfile, String> {
    List<UserProfile> findByPersonalInfo_UserId(String userId);
}

但是在代码中调用此方法时,我收到以下错误.不确定我正在使用的 redis/spring 库是否存在问题.我正在使用

But on calling this method in code, i get the below error. Not sure if there is an issue with the redis/spring libraries i am using. I am using

  • springboot-starter-parent 版本:1.5.2.RELEASE
  • spring-data-redis 版本:1.8.6.RELEASE

异常:

java.lang.NoSuchMethodError: org.springframework.data.keyvalue.core.query.KeyValueQuery.getCriteria()Ljava/lang/Object;
    at org.springframework.data.redis.repository.query.RedisQueryCreator.complete(RedisQueryCreator.java:101) ~[spring-data-redis-1.8.6.RELEASE.jar:na]
    at org.springframework.data.redis.repository.query.RedisQueryCreator.complete(RedisQueryCreator.java:41) ~[spring-data-redis-1.8.6.RELEASE.jar:na]
    at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:88) ~[spring-data-commons-1.13.1.RELEASE.jar:na]
    at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:73) ~[spring-data-commons-1.13.1.RELEASE.jar:na]
    at org.springframework.data.keyvalue.repository.query.KeyValuePartTreeQuery.createQuery(KeyValuePartTreeQuery.java:184) ~[spring-data-keyvalue-1.2.1.RELEASE.jar:na]
    at org.springframework.data.keyvalue.repository.query.KeyValuePartTreeQuery.prepareQuery(KeyValuePartTreeQuery.java:128) ~[spring-data-keyvalue-1.2.1.RELEASE.jar:na]
    at org.springframework.data.keyvalue.repository.query.KeyValuePartTreeQuery.execute(KeyValuePartTreeQuery.java:87) ~[spring-data-keyvalue-1.2.1.RELEASE.jar:na]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:483) ~[spring-data-commons-1.13.1.RELEASE.jar:na]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461) ~[spring-data-commons-1.13.1.RELEASE.jar:na]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61) ~[spring-data-commons-1.13.1.RELEASE.jar:na]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57) ~[spring-data-commons-1.13.1.RELEASE.jar:na]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at com.sun.proxy.$Proxy66.findByPersonalInfo_UserId(Unknown Source) ~[na:na]

更新 2:我能够通过将 springboot 版本更改为 1.5.6.RELEASE 来修复上述异常.

Update 2: I was able to fix the above exception by changing the springboot version to 1.5.6.RELEASE.

但是,现在我面临的问题是,当我通过 userid 查询时,即使存在匹配项,它也不会给我 UserProfiles.

However, now the issue i am facing is, when i query by userid, it doesnt give me the UserProfiles, even though there is a match.

例如 redis-cli 显示:

For example, redis-cli shows:

KEYS *
UserProfile:d0876c1f-5684-4ee4-acbb-7a92b7fa25ae
UserProfile:3591e476-29d7-4c3c-a7e5-6272231f96e0
UserProfile:3591e476-29d7-4c3c-a7e5-6272231f96e0:idx
UserProfile:d0876c1f-5684-4ee4-acbb-7a92b7fa25ae:idx
UserProfile:51814a77-bf40-4912-b700-cfa50d1c4b25
UserProfile:personalInfo.userId:adrian.tremblay
UserProfile:66ba8276-1bb0-47a0-a54d-4c9d99b8bf80
UserProfile:66ba8276-1bb0-47a0-a54d-4c9d99b8bf80:idx
UserProfile:personalInfo.userId:anthony.turner
UserProfile:personalInfo.userId:ashleigh.hayes
UserProfile:a81356b0-27ef-4a34-92a3-629be5114f0e
UserProfile

当我执行 findAll、findById 时,它会返回结果.当我执行 findByPersonalInfo_UserId() 并传递诸如 anthony.turner 或 ashleigh.hayes 之类的值时,没有任何显示.我是否以某种不正确的格式提供了 userId?我尝试了一些不同的东西,但没有奏效.

When i do a findAll, findById, it gives me results back. When I do a findByPersonalInfo_UserId(), and pass values like: anthony.turner or ashleigh.hayes, nothing shows up. Am i giving the userId in some incorrect format? I tried a few different things, but didnt work.

更新 3:我还尝试删除 UserProfile 对象中的 @Reference(以便 redis 对象变平,而不是指向引用).但这也无济于事.

Update 3: I also tried removing the @Reference in the UserProfile object (so that the redis objects get flattened out, instead of pointing to references). But this didn't help either.

推荐答案

我遇到了同样的情况,

基本上,如果你有一个引用,那么 Redis 在内部存储引用的 Id,不能直接查询,因为它需要获取整个对象来匹配,是的,它是 Redis(或任何基于哈希/非关系数据库)的缺点).

Basically if you have a reference then Redis internally stores the Id for the reference, which cannot be directly queried as it need to fetch the whole Object to match, yep its the drawback for Redis(or any Hashbased/Non-relational database).

您可能会问为什么不可能,从技术上讲是可以做到的,但这将是处理器和内存密集型操作,最终会影响性能,而 Redis 以其性能而闻名.

You may ask why not possible, technically it can be done but it will be processor and memory intensive operation which will ultimately hit performance, and Redis is known for its performance.

@Reference 仅当您希望在多个对象(此处为 UserInfo)之间共享单个对象(此处为 PersonalInfo)时才应使用.

@Reference should only be used only and only when you wish to share a single object (here PersonalInfo) among multiple Objects (here UserInfo).

如果您想使用 @Reference 的可能解决方案(假设 UserProfile 的 'id' 不等于 PersonalInfo 的 userId ):

Possible solutions if you want to use @Reference (assuming UserProfile's 'id' not equal to PersonalInfo's userId ):

我在这个答案结尾的个人解决方案:

My personal solution at this answer's end :

  1. (不推荐 - 性能缓慢)- 首先 findAllUserProfile() 然后遍历 UserProfile 中存在的每个 PersonalInfo 并匹配所需的字段(此处为 userId)

  1. (Not Recommended - slow performance) - first findAllUserProfile() then go through each PersonalInfo present in UserProfile and match desired field (here userId)

(推荐)- 重构您的架构,问我为什么,因为如果您希望保留引用而不仅仅是阅读(我的意思也是查询),那么在这种情况下非关系型数据库不适合您.如果可能,进行重组以使其适合非关系结构.

(Recommended) - Restructuring your schema, ask me why, because if you wish to keep references for more than just reading (i mean for querying too) then non-relational database is not one for you in this situation. Restructure to make it fit in non-relational structure if possible.

注意:上面@Aurimas 的解决方案很好,最适合您的情况,如果您不放置引用,那么它将创建一个新对象,该对象将存储在 UserProfile 对象,但 PersonalInfo 中的任何更改都将特定于此 UserProfile 并且不会反映在其他 UserProfile 对象中.但它的优点是可以查询:-)

Note: solution by @Aurimas above is good and suits your situation best, if you won't put reference then it will create a new object which will be stored in UserProfile object but any changes in PersonalInfo will be specific to this UserProfile and won't reflect in other UserProfile objects. But it's advantage is it will be query-able :-)

因此,根据您的情况,我会建议为 PersonalInfo 放弃 @Reference,因为它在逻辑上不应该被共享(即 Personal ;-) ),然后继续使用@Aurimas 解决方案.

So as per you situation I will recommend to ditch the @Reference for PersonalInfo as logically it should not be shared (i.e Personal ;-) ), and go ahead with @Aurimas solution.

这篇关于使用 Spring Data 查询 Redis 中的嵌套对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆