Creating Spring Data Solr Repositories

In Spring Data Solr Repositories article we will discuss about Spring Data repository, Spring Data project provides Spring Data Repository abstraction to reduce the amount of boilerplate code. Earlier there are various persistence stores require lot of code for data access layers implementation. Spring Data repository abstraction almost avoid all code required to implement data access layers.

Spring Data Solr Repositories

Repository is a central interface of the Spring Data repository abstraction. As you can see in the above diagram, the Spring Data project is not only for a particular technologies such as relational databases it is also for NoSQL databases such as MongoDB, Cassandra, Solr etc. But Repository interface is a central interface for all various technologies. It takes the domain class to manage as well as ID type of the domain class as type arguments.

This Repository interface act as a marker interface but Spring Data provides another interface that extend this Repository interface. The name of this interface is CrudRepository, it provides sophisticated CRUD functionality for the entity class that is being managed. Let’s see as following:

public interface CrudRepository<T, ID extends Serializable>
extends Repository<T, ID> {

<S extends T> S save(S entity);

Optional<T> findById(ID primaryKey);

Iterable<T> findAll();

long count();

void delete(T entity);

boolean existsById(ID primaryKey);

//... more functionality omitted.
}

As you can see the above interface provides several methods, that are required for Data Access layer. As following:

  • S save(S entity)– This method saves the given entity.
  • findById(ID primaryKey)– This method returns the entity identified by the given ID.
  • findAll()– This method is responsible for returning all entities.
  • count()– This method will be used to return the number of entities.
  • delete(T entity)– This method deletes the given entity.
  • existsById(ID primaryKey)– It indicates whether an entity with the given ID exists.

The Spring Data project also provides support for pagination and sorting. The Spring Data repositories has another repository interface that extends CrudRepository to provide pagination and sorting functionalities, that is PagingAndSortingRepository. It is abstraction that adds additional methods to ease paginated access to entities as following:

public interface PagingAndSortingRepository<T, ID extends Serializable>
extends CrudRepository<T, ID> {

Iterable<T> findAll(Sort sort);

Page<T> findAll(Pageable pageable);
}

The above interface adds two more methods, findAll(Sort sort) returns sorted entities and findAll(Pageable pageable) returns results into paginated form. Let’s see how to access the second page of Order by page size of 10 as following:

PagingAndSortingRepository<User, Long> repository = //... get access to a bean
Page<Order> orders = repository.findAll(PageRequest.of(1, 10));

As we have seen that how to access paginated results using the PagingAndSortingRepository interface. Let’s see the how to create Spring Data Solr repositories.

Creating Spring Data Solr repositories

Spring Data project also provides persistence technology-specific abstractions, such as SolrCrudRepository, MongoCrudRepository, JpaCrudRepository etc. These interfaces extend CrudRepository and expose the functionalities of the specific persistence technology.

First, define a domain class-specific repository interface. The interface must extend Repository and be typed to the domain class and an ID type. If you want to expose CRUD methods for that domain type, extend CrudRepository instead of Repository.

package com.doj.app.repository;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.solr.repository.Query;
import org.springframework.data.solr.repository.SolrCrudRepository;

import com.doj.app.pojo.Order;

/**
* @author Dinesh.Rajput
*
*/
public interface SolrOrderRepository extends SolrCrudRepository<Order, Long> {

Order findByOrderid(Long orderid);
...

}

Document Mapping

In the above repository class, Order is a domain class as following:

/**
 * 
 */
package com.doj.app.pojo;

import org.springframework.data.annotation.Id;
import org.springframework.data.solr.core.mapping.Indexed;
import org.springframework.data.solr.core.mapping.SolrDocument;

/**
 * @author Dinesh.Rajput
 *
 */
@SolrDocument(collection="Order")
public class Order {
    
    @Id
    @Indexed(name = "oid", type = "long")
    private Long orderid;
 
    @Indexed(name = "oname", type = "string")
    private String orderName;
    
    @Indexed(name = "odesc", type = "string")
    private String orderDescription;
    
    @Indexed(name = "pname", type = "string")
    private String productName;

    @Indexed(name = "cname", type = "string")
    private String customerName;
    
    @Indexed(name = "cmobile", type = "string")
    private String customerMobile;

	public Long getOrderid() {
		return orderid;
	}

	public void setOrderid(Long orderid) {
		this.orderid = orderid;
	}

	public String getOrderName() {
		return orderName;
	}

	public void setOrderName(String orderName) {
		this.orderName = orderName;
	}

	public String getProductName() {
		return productName;
	}

	public void setProductName(String productName) {
		this.productName = productName;
	}

	public String getCustomerName() {
		return customerName;
	}

	public void setCustomerName(String customerName) {
		this.customerName = customerName;
	}

	public String getCustomerMobile() {
		return customerMobile;
	}

	public void setCustomerMobile(String customerMobile) {
		this.customerMobile = customerMobile;
	}

	public String getOrderDescription() {
		return orderDescription;
	}

	public void setOrderDescription(String orderDescription) {
		this.orderDescription = orderDescription;
	}
    
}

The above class is domain class for Spring Data Solr repository. Let’s see in the next section how to configure Solr repository using Spring Namespace.

Spring Data Solr Namespace

The Spring Data Solr module contains a custom namespace.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:solr="http://www.springframework.org/schema/data/solr"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/solr
http://www.springframework.org/schema/data/solr/spring-solr.xsd">

<solr:repositories base-package="com.dineshonjava.repositories" />
<solr:solr-client id="solrClient" url="http://locahost:8983/solr" />

</beans>

Using the solr-client element registers an instance of SolrClient in the context. Let’s configure same above configuration using the Annotation based configuration.

Annotation based configuration

The Spring Data Solr repositories support cannot only be activated through an XML namespace but also using an annotation through JavaConfig.

@Configuration
@EnableSolrRepositories
class ApplicationConfig {

  @Bean
  public SolrClient solrClient() {
    EmbeddedSolrServerFactory factory = new EmbeddedSolrServerFactory("classpath:com/dineshonjava/solr");
    return factory.getSolrServer();
  }

  @Bean
  public SolrOperations solrTemplate() {
    return new SolrTemplate(solrClient());
  }
}

In the above configuration, we have enabled Spring Data Solr repository using the @EnableSolrRepositories annotation, which essentially carries the same attributes as the XML namespace does. We can also give basePackage attribute to scan all available repositories.

Let’s see how to create Query methods in Solr Repository in the next section.

Query methods in Solr Repository

The Solr module supports defining a query manually as String or have it being derived from the method name. So deriving the query from the method name is not always sufficient and/or may result in unreadable method names. We can also use the @Query annotation or Solr named queries.

Query creation from method names

public interface SolrOrderRepository extends SolrCrudRepository<Order, Long> {

List findByOrderidAndOrderName(Long orderid, String orderName);
}

The method name above will be translated into the following solr query

q=oid:?0 AND oname:?1

Using @Query Annotation

You can also bind your own query to query method of the Spring Data Solr repositories using @Query annotation as following:

public interface SolrOrderRepository extends SolrCrudRepository<Order, Long> {

...

@Query("odesc:*?0*")
Page<Order> findByOrderDescription(String searchTerm, Pageable pageable);

@Query("odesc:*?0* OR oname:*?0* OR pname:*?0*")
Page<Order> findByCustomerQuery(String searchTerm, Pageable pageable);

}

Using NamedQueries

You can also use named queries by declring into properties file in the classpath and load this the properties file at the time configuration for the Spring Data Solr repositories.

Declare named query in properties file

Order.findByNamedQuery=odesc:?0
Order.findByOrderName=oname:?0

public interface SolrOrderRepository extends SolrCrudRepository<Order, Long> {

List<Order, Long> findByNamedQuery(String orderDesc);

@Query(name = "Order.findByOrderName")
List<Order, Long> findByAnnotatedNamedQuery(String name);

}

According Spring Document for the Spring Data Solr, following query methods are supported.

Supported keywords inside method names
Keyword Sample Solr Query String

And

findByNameAndPopularity

q=name:?0 AND popularity:?1

Or

findByNameOrPopularity

q=name:?0 OR popularity:?1

Is

findByName

q=name:?0

Not

findByNameNot

q=-name:?0

IsNull

findByNameIsNull

q=-name:[* TO *]

IsNotNull

findByNameIsNotNull

q=name:[* TO *]

Between

findByPopularityBetween

q=popularity:[?0 TO ?1]

LessThan

findByPopularityLessThan

q=popularity:[* TO ?0}

LessThanEqual

findByPopularityLessThanEqual

q=popularity:[* TO ?0]

GreaterThan

findByPopularityGreaterThan

q=popularity:{?0 TO *]

GreaterThanEqual

findByPopularityGreaterThanEqual

q=popularity:[?0 TO *]

Before

findByLastModifiedBefore

q=last_modified:[* TO ?0}

After

findByLastModifiedAfter

q=last_modified:{?0 TO *]

Like

findByNameLike

q=name:?0*

NotLike

findByNameNotLike

q=-name:?0*

StartingWith

findByNameStartingWith

q=name:?0*

EndingWith

findByNameEndingWith

q=name:*?0

Containing

findByNameContaining

q=name:*?0*

Matches

findByNameMatches

q=name:?0

In

findByNameIn(Collection<String>
names)

q=name:(?0…​ )

NotIn

findByNameNotIn(Collection<String>
names)

q=-name:(?0…​ )

Within

findByStoreWithin(Point, Distance)

q={!geofilt pt=?0.latitude,?0.longitude sfield=store
d=?1}

Near

findByStoreNear(Point, Distance)

q={!bbox pt=?0.latitude,?0.longitude sfield=store
d=?1}

Near

findByStoreNear(Box)

q=store[?0.start.latitude,?0.start.longitude TO
?0.end.latitude,?0.end.longitude]

True

findByAvailableTrue

q=inStock:true

False

findByAvailableFalse

q=inStock:false

OrderBy

findByAvailableTrueOrderByNameDesc

q=inStock:true&sort=name desc

Thanks for reading with the Dineshonjava. Let’s we have lot of articles in the series of the Spring Data Solr tutorial.

Happy learning with us!!! 🙂

Previous
Next

One Response

  1. decinti June 27, 2018