Integrating Elasticsearch with Spring Boot for Full-Text Product Search

This guide walks through installing Elasticsearch and Kibana, configuring a Chinese analyzer, defining Spring Data Elasticsearch annotations, creating repository and service layers, building a REST controller, and testing product search functionality within a Spring Boot mall application.

macrozheng
macrozheng
macrozheng
Integrating Elasticsearch with Spring Boot for Full-Text Product Search

Project Framework Overview

The article explains how to integrate Elasticsearch into a mall project to enable full‑text search for product information. It covers installation, configuration, data mapping, repository creation, service implementation, and API testing.

Elasticsearch

Elasticsearch is a distributed, scalable, real‑time search and analytics engine. It provides full‑text search and real‑time data statistics from the start of a project.

Installation and Usage

Download the Elasticsearch 6.2.2 zip package from https://www.elastic.co/cn/downloads/past-releases/elasticsearch-6-2-2 and unzip it.

Install the Chinese analysis plugin:

elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.2.2/elasticsearch-analysis-ik-6.2.2.zip

Start Elasticsearch by running bin\elasticsearch.bat.

Kibana

Download Kibana 6.2.2 zip from https://artifacts.elastic.co/downloads/kibana/kibana-6.2.2-windows-x86_64.zip and unzip it.

Start Kibana with bin\kibana.bat and open http://localhost:5601 in a browser.

Kibana UI
Kibana UI

Spring Data Elasticsearch

Spring Data Elasticsearch provides a Spring‑Data‑style way to operate on Elasticsearch, reducing boilerplate code.

Common Annotations

@Document – maps a class to an Elasticsearch document.

/**
 * Marks the class as an Elasticsearch document.
 */
@Document(indexName = "pms", type = "product", shards = 1, replicas = 0)
public class EsProduct implements Serializable {
    private static final long serialVersionUID = -1L;

    @Id
    private Long id;

    @Field(type = FieldType.Keyword)
    private String productSn;

    @Field(type = FieldType.Keyword)
    private String brandName;

    @Field(type = FieldType.Keyword)
    private String productCategoryName;

    @Field(analyzer = "ik_max_word", type = FieldType.Text)
    private String name;

    @Field(analyzer = "ik_max_word", type = FieldType.Text)
    private String subTitle;

    @Field(analyzer = "ik_max_word", type = FieldType.Text)
    private String keywords;

    // other fields omitted for brevity
}

@Id – marks the field as the document ID.

@Field – defines field type, analyzer, indexing, and storage options.

@Field(type = FieldType.Keyword) // not tokenized, suitable for exact matches
private String productSn;

@Field(analyzer = "ik_max_word", type = FieldType.Text) // tokenized for full‑text search
private String name;

Derived Queries

By extending ElasticsearchRepository, common CRUD methods are available, and query methods can be defined directly from the method name.

public interface EsProductRepository extends ElasticsearchRepository<EsProduct, Long> {
    Page<EsProduct> findByNameOrSubTitleOrKeywords(String name, String subTitle, String keywords, Pageable page);
}

Service Layer

The EsProductService interface defines operations for importing, creating, and deleting product documents.

public interface EsProductService {
    /** Import all products from the database into Elasticsearch */
    int importAll();

    /** Delete a product by ID */
    void delete(Long id);

    /** Create a product document by ID */
    EsProduct create(Long id);

    /** Batch delete products */
    void delete(List<Long> ids);

    /** Search by keyword with pagination */
    Page<EsProduct> search(String keyword, Integer pageNum, Integer pageSize);
}

The implementation uses a DAO to fetch product data, then saves it via the repository.

@Service
public class EsProductServiceImpl implements EsProductService {
    private static final Logger LOGGER = LoggerFactory.getLogger(EsProductServiceImpl.class);

    @Autowired
    private EsProductDao productDao;

    @Autowired
    private EsProductRepository productRepository;

    @Override
    public int importAll() {
        List<EsProduct> esProductList = productDao.getAllEsProductList(null);
        Iterable<EsProduct> saved = productRepository.saveAll(esProductList);
        int count = 0;
        for (EsProduct p : saved) {
            count++;
        }
        return count;
    }

    @Override
    public void delete(Long id) {
        productRepository.deleteById(id);
    }

    @Override
    public EsProduct create(Long id) {
        List<EsProduct> list = productDao.getAllEsProductList(id);
        if (!list.isEmpty()) {
            EsProduct esProduct = list.get(0);
            return productRepository.save(esProduct);
        }
        return null;
    }

    @Override
    public void delete(List<Long> ids) {
        List<EsProduct> esProductList = new ArrayList<>();
        for (Long id : ids) {
            EsProduct esProduct = new EsProduct();
            esProduct.setId(id);
            esProductList.add(esProduct);
        }
        productRepository.deleteAll(esProductList);
    }

    @Override
    public Page<EsProduct> search(String keyword, Integer pageNum, Integer pageSize) {
        Pageable pageable = PageRequest.of(pageNum, pageSize);
        return productRepository.findByNameOrSubTitleOrKeywords(keyword, keyword, keyword, pageable);
    }
}

Controller Layer

The REST controller exposes endpoints for importing data, deleting, creating, and searching products.

@Controller
@Api(tags = "EsProductController", description = "Product search management")
@RequestMapping("/esProduct")
public class EsProductController {
    @Autowired
    private EsProductService esProductService;

    @ApiOperation("Import all products from DB to ES")
    @RequestMapping(value = "/importAll", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult<Integer> importAllList() {
        int count = esProductService.importAll();
        return CommonResult.success(count);
    }

    @ApiOperation("Delete product by ID")
    @RequestMapping(value = "/delete/{id}", method = RequestMethod.GET)
    @ResponseBody
    public CommonResult<Object> delete(@PathVariable Long id) {
        esProductService.delete(id);
        return CommonResult.success(null);
    }

    @ApiOperation("Batch delete products by IDs")
    @RequestMapping(value = "/delete/batch", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult<Object> delete(@RequestParam("ids") List<Long> ids) {
        esProductService.delete(ids);
        return CommonResult.success(null);
    }

    @ApiOperation("Create product document by ID")
    @RequestMapping(value = "/create/{id}", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult<EsProduct> create(@PathVariable Long id) {
        EsProduct esProduct = esProductService.create(id);
        if (esProduct != null) {
            return CommonResult.success(esProduct);
        }
        return CommonResult.failed();
    }

    @ApiOperation("Simple keyword search")
    @RequestMapping(value = "/search/simple", method = RequestMethod.GET)
    @ResponseBody
    public CommonResult<CommonPage<EsProduct>> search(
            @RequestParam(required = false) String keyword,
            @RequestParam(required = false, defaultValue = "0") Integer pageNum,
            @RequestParam(required = false, defaultValue = "5") Integer pageSize) {
        Page<EsProduct> esProductPage = esProductService.search(keyword, pageNum, pageSize);
        return CommonResult.success(CommonPage.restPage(esProductPage));
    }
}

Interface Testing

Import Data from Database to Elasticsearch

Import result
Import result
Import success
Import success

Product Search

Search UI
Search UI
Search results
Search results

Project Source Code

https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-06

Recommended Reading

mall architecture and feature overview

Required knowledge for mall learning (recommended resources)

Integrating SpringBoot+MyBatis to build a basic skeleton

Integrating Swagger‑UI for online API documentation

Integrating Redis for caching

SpringSecurity + JWT authentication (part 1)

SpringSecurity + JWT authentication (part 2)

Integrating SpringTask for scheduled jobs

QR code
QR code

Follow us and give a like!

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

javaElasticsearchSpring Bootspring-dataFull‑Text Search
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.