How do I search for a nested @Indexed key in Redis redis-om-spring?

499 views Asked by At

I am trying to search for a nested @Indexed field using redis-om-spring

For some reason a find returns expected 1 entry for level 1, but returns unexpected 0 entries for level 2.

I am not sure if I can only search one level deep or if I am making a mistake.

@SpringBootApplication
@Configuration
@EnableRedisDocumentRepositories
@Slf4j
public class Application {
  
  @Autowired
  ProductRepository productRepository;

  @Bean
  CommandLineRunner loadTestData() {
    return args -> {
      productRepository.deleteAll();

      productRepository.save(new Product(new MyKey(new MyId("A_level2Key1"),"A_level1Key1"),"FirstColour"));
      productRepository.save(new Product(new MyKey(new MyId("B_level2Key1"),"B_level1Key1"),"SecondColour"));


      var byMyKeyLevel1Key = productRepository.findByMyKeyLevel1Key("A_level1Key1");
      System.out.println(byMyKeyLevel1Key.size());//returns expected 1 entry for level 1

      var byMyKeyMyIdLevel2Key = productRepository.findByMyKeyMyIdLevel2Key("A_level2Key1");
      System.out.println(byMyKeyMyIdLevel2Key.size());//returns unexpected 0 entries for level 2
    };
  }

  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }

}

Product

import com.redis.om.spring.annotations.Document;
import com.redis.om.spring.annotations.Indexed;
import com.redis.om.spring.annotations.Searchable;
@Slf4j
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document
public class Product {
    @Indexed
    @Id
    private MyKey myKey;

    @Searchable
    @NonNull
    private String colourDesc;
}

ProductRepository

public interface ProductRepository extends RedisDocumentRepository<Product, String> {
    List<Product> findByMyKeyLevel1Key(String level1Key);

    List<Product> findByMyKeyMyIdLevel2Key(String level2Key);
}

MyKey

import com.redis.om.spring.annotations.Indexed;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class MyKey {
    @Indexed
    MyId myId;
    @Indexed
    String level1Key;
}

Data in Redis:

Redis Data

FT.INFO "com.redis.om.documents.domain.ProductIdx"

From the logs, it generates searches:

FT.SEARCH "com.redis.om.documents.domain.ProductIdx" @myKey_level1Key:{A_level1Key1}

FT.SEARCH "com.redis.om.documents.domain.ProductIdx" @myKey_myId_level2Key:{A_level2Key1}

Index

I start Redis with:

docker run -d --name redis-stack -p 6379:6379 -p 8001:8001 redis/redis-stack:latest
1

There are 1 answers

0
BSB On BEST ANSWER

The issue is likely in the naming of the repository methods. I wrote your example as a test in the project repo, this will be using release 0.7.0 - but it should work with 0.6.x-SNAPSHOTs:

The entity:

@Data @AllArgsConstructor @NoArgsConstructor @Document public class Product {
  @Indexed @Id private MyKey myKey;

  @Searchable @NonNull private String colourDesc;
}

The first-level key:

@Data @AllArgsConstructor @NoArgsConstructor public class MyKey {
  @Indexed MyId myId;
  @Indexed String level1Key;

  @Override public String toString() {
    return myId.toString();
  }
}

The second-level key:

@Data @AllArgsConstructor @NoArgsConstructor public class MyId {
  @Indexed
  private String level2Key;

  @Override public String toString() {
    return level2Key;
  }
}

The repo, here's where things probably went wrong for you...

public interface ProductRepository extends RedisDocumentRepository<Product, MyKey> {
  List<Product> findByMyKey_Level1Key(String level1Key);

  List<Product> findByMyKey_MyId_Level2Key(String level2Key);
}

and here's a snippet of the test class I used:

  @Autowired ProductRepository productRepository;
  @BeforeEach
  void setup() {
    productRepository.deleteAll();

    productRepository.save(new Product(new MyKey(new MyId("A_level2Key1"),"A_level1Key1"),"FirstColour"));
    productRepository.save(new Product(new MyKey(new MyId("B_level2Key1"),"B_level1Key1"),"SecondColour"));
  }

  @Test
  void testFindNestedKeyValues() {
    var byMyKeyLevel1Key = productRepository.findByMyKey_Level1Key("A_level1Key1");
    assertThat(byMyKeyLevel1Key).map(Product::getMyKey).map(MyKey::getLevel1Key).containsExactly("A_level1Key1");

    var byMyKeyMyIdLevel2Key = productRepository.findByMyKey_MyId_Level2Key("A_level2Key1");
    assertThat(byMyKeyMyIdLevel2Key).map(Product::getMyKey).map(MyKey::getMyId).map(MyId::getLevel2Key).containsExactly("A_level2Key1");
  }

Hope that helps! Thanks for trying Redis OM Spring!