-2

I'm making online shop with Spring and I decided to add text-search there. I tried Hibernate Search using this guide https://reflectoring.io/hibernate-search/ and got an error while starting the app.

Here's what I have (error) + my code below:

Description:

An attempt was made to call a method that does not exist. The attempt was made from the following location:

org.hibernate.search.elasticsearch.client.impl.DefaultElasticsearchClientFactory.createClient(DefaultElasticsearchClientFactory.java:92)

The following method did not exist:

org.elasticsearch.client.RestClientBuilder.setMaxRetryTimeoutMillis(I)Lorg/elasticsearch/client/RestClientBuilder;

The method's class, org.elasticsearch.client.RestClientBuilder, is available from the following locations:

jar:file:/C:/Users/myuser/.m2/repository/org/elasticsearch/client/elasticsearch-rest-client/7.9.3/elasticsearch-rest-client-7.9.3.jar!/org/elasticsearch/client/RestClientBuilder.class

The class hierarchy was loaded from the following locations:

org.elasticsearch.client.RestClientBuilder: file:/C:/Users/myuser/.m2/repository/org/elasticsearch/client/elasticsearch-rest-client/7.9.3/elasticsearch-rest-client-7.9.3.jar

Action:

Correct the classpath of your application so that it contains a single, compatible version of org.elasticsearch.client.RestClientBuilder

And there are classes that I've created (due to the guide): Item.class

@Data
@Entity
@Component
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "items")
@Indexed(index = "items")
@NormalizerDef(name = "lowercase", filters = @TokenFilterDef(factory = LowerCaseFilterFactory.class))
public class Item {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long itemId;

    @Field(name = "name", analyzer = @Analyzer(definition = "stop"))
    private String itemName;

    @Field(name = "description", analyzer = @Analyzer(definition = "stop"))
    @Field(name = "name", analyzer = @Analyzer(definition = "stop"))
    private String itemDesc;

    @Field(normalizer = @Normalizer(definition = "lowercase"))
    @Enumerated(EnumType.STRING)
    private ItemCategory itemCategory;

IndexingService.class

@Service
@RequiredArgsConstructor
@Slf4j
public class IndexingService {

    private final EntityManager em;

    @Transactional  // check
    public void initiateIndexing() throws InterruptedException {
        log.info("Initiating indexing...");
        FullTextEntityManager fullTextEntityManager =
                Search.getFullTextEntityManager(em);
        fullTextEntityManager.createIndexer().startAndWait();
        log.info("All entities indexed");
    }
}

SearchService.class

@Component
@Slf4j
@RequiredArgsConstructor
public class SearchService {

    private final EntityManager entityManager;

    public List<Item> getItemBasedOnWord(String word){
        FullTextEntityManager fullTextEntityManager =
                Search.getFullTextEntityManager(entityManager);

        QueryBuilder qb = fullTextEntityManager
                .getSearchFactory()
                .buildQueryBuilder()
                .forEntity(Item.class)
                .get();

        Query itemQuery = qb.keyword()
                .onFields("name","description")
                .matching(word)
                .createQuery();

        FullTextQuery fullTextQuery = fullTextEntityManager
                .createFullTextQuery(itemQuery, Item.class);
        return (List<Item>) fullTextQuery.getResultList();
    }
}

StartupEvent.class

@Component
@Slf4j
@RequiredArgsConstructor
public class StartupEvent implements ApplicationListener<ApplicationReadyEvent> {

    private final IndexingService indexingService;

    @Override
    public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
        try {
            indexingService.initiateIndexing();
        } catch (InterruptedException ex){
            log.error("Failed to reindex entities ", ex);
        }
    }
}

And finally Elasticsearch Config class:

@Configuration
public class EsConfig {

    @Bean
    public Client client() throws UnknownHostException {
        Settings settings = Settings.builder().put("cluster.name", "elasticsearch").put("client.transport.sniff", true).build();
        TransportClient transportClient = new PreBuiltTransportClient(settings);
        transportClient.addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9200)); // 9300
        return transportClient;
    }
}

What should I add here to prevent this error? I can add additional code if you need. Hope you help me, guys!

Aftermaz
  • 29
  • 5

1 Answers1

0

You are using Hibernate Search 5, which is old, with a recent version of Spring.

Hibernate Search 5, being old, depends on an old version of the Elasticsearch client JARs.

Your version of Spring depends on a newer, incompatible version of the Elasticsearch client JARs.

Two solutions:

  1. Upgrade to the newer Hibernate Search 6, which will most likely depend on a version of Elasticsearch that is compatible with the one bundled with Spring. Note that just changing the version won't be enough: group IDs, artifact IDs and APIs are different. See the migration guide.

  2. OR try to downgrade to an older version of the Elasticsearch client. For example, with Spring Boot:

    <properties>
        <elasticsearch.version>5.6.16</elasticsearch.version>
        <!-- ... plus any other properties of yours ... -->
    </properties>
    
yrodiere
  • 9,280
  • 1
  • 13
  • 35
  • Thank you so much! It did helped me! However, it created plenty of new errors but it's another story. I will try to cope with them. – Aftermaz Apr 28 '21 at 12:09