mall integrates Elastic search to realize commodity search

Keywords: Java ElasticSearch Spring Database

SpringBoot e-commerce project mall (20k+star) address: https://github.com/macrozheng/mall

abstract

This paper mainly explains the process of mall integrating Elastic search to realize the import, query, modification and deletion of commodity information in Elastic search.

Introduction to Project Usage Framework

Elasticsearch

Elastic search is a distributed, scalable, real-time search and data analysis engine. It gives you the ability to search, analyze and explore data from the beginning of the project, and can be used to achieve full-text search and real-time data statistics.

Installation and Use of Elasticsearch

  1. Download the zip package of Elastic search 6.2.2 and extract it to the specified directory. Download the address: https://www.elastic.co/cn/downloads/past-releases/elasticsearch-6-2-2

  1. Install the Chinese word segmentation plug-in and execute the following commands in the elastic search-6.2.2bin directory: elastic search-plugin install https://github.com/medcl/elas...

  1. Run elastic search. bat under bin directory to start Elastic search

  1. Download Kibana as a client to access Elastic search. Download the 6.2.2 zip package and extract it to the specified directory. Download the address: https://artifacts.elastic.co/downloads/kibana/kibana-6.2.2-windows-x86_64.zip

  1. Run kibana.bat under bin directory to start Kibana's user interface

  1. Visit http://localhost:5601 You can open Kibana's user interface

Spring Data Elasticsearch

Spring Data Elastic search is a Spring-provided way to manipulate data storage in Spring Data style, which can avoid writing a lot of template code.

Common Notes

@Document
//Marking Domain Objects Mapped to Elastic Search Documents
public @interface Document {
  //Index database ranking, the concept of database in mysql
    String indexName();
  //Document type, the concept of tables in mysql
    String type() default "";
  //Default number of fragments
    short shards() default 5;
  //Default number of copies
    short replicas() default 1;

}

@Id

//Representation is the id of the document, which can be considered the concept of table rows in mysql
public @interface Id {
}

@Field

public @interface Field {
  //Types of fields in documents
    FieldType type() default FieldType.Auto;
  //Whether to establish inverted index
    boolean index() default true;
  //Storage or not
    boolean store() default false;
  //Segmenter rank
    String analyzer() default "";
}
//Automatically specify metadata types for documents
public enum FieldType {
    Text,//Word segmentation is performed and the character type of the index is established.
    Integer,
    Long,
    Date,
    Float,
    Double,
    Boolean,
    Object,
    Auto,//Automatically determine field type
    Nested,//Nested object types
    Ip,
    Attachment,
    Keyword//Types of indexing that do not perform word segmentation
}

Data Operation in Sping Data Mode

Common data manipulation methods can be obtained by inheriting Elastic search Repository interface

Derivative queries can be used

The query method name can be directly specified in the interface. Without implementation, such as commodity name, title and keyword in the commodity table, the following query can be directly defined, and the three fields can be searched in full text.

    /**
     * Search query
     *
     * @param name              Name of commodity
     * @param subTitle          Commodity Title
     * @param keywords          Commodity keywords
     * @param page              Paging information
     * @return
     */
    Page<EsProduct> findByNameOrSubTitleOrKeywords(String name, String subTitle, String keywords, Pageable page);

The corresponding fields are prompted directly in the idea

Using the @Query annotation, you can query with the DSL statement of Elastic search
@Query("{"bool" : {"must" : {"field" : {"name" : "?0"}}}}")
Page<EsProduct> findByName(String name,Pageable pageable);

Description of Project Use Table

  • pms_product: Commodity Information Table
  • pms_product_attribute: Commodity attribute parameter table
  • pms_product_attribute_value: A table that stores product parameter values

Integrating Elastic search to realize commodity search

Adding dependencies to pom.xml

<!--Elasticsearch Relevant dependency-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch<artifactId>
</dependency>

Modify SpringBoot configuration file

Modify the application.yml file and add Elastic search related configuration under the spring node.

data:
  elasticsearch:
    repositories:
      enabled: true
    cluster-nodes: 127.0.0.1:9300 # Connecting address and port number of es
    cluster-name: elasticsearch # Name of es cluster

Add commodity document object EsProduct

Fields without Chinese word segmentation need to be set to the @Field(type = FieldType.Keyword) type, and Chinese word segmentation needs to be set to the @Field (analyzer = ik_max_word), type = FieldType. Text) type.

package com.macro.mall.tiny.nosql.elasticsearch.document;

import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;

/**
 * Commodity Information in Search
 * Created by macro on 2018/6/19.
 */
@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;
    private Long brandId;
    @Field(type = FieldType.Keyword)
    private String brandName;
    private Long productCategoryId;
    @Field(type = FieldType.Keyword)
    private String productCategoryName;
    private String pic;
    @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;
    private BigDecimal price;
    private Integer sale;
    private Integer newStatus;
    private Integer recommandStatus;
    private Integer stock;
    private Integer promotionType;
    private Integer sort;
    @Field(type =FieldType.Nested)
    private List<EsProductAttributeValue> attrValueList;

    //All getter and setter methods are omitted
}

Add the EsProduct Repository interface to operate Elastic search

By inheriting the Elastic search Repository interface, we have some basic data manipulation methods for Elastic search and define a derivative query method.

package com.macro.mall.tiny.nosql.elasticsearch.repository;

import com.macro.mall.tiny.nosql.elasticsearch.document.EsProduct;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

/**
 * Commodity ES Operating Class
 * Created by macro on 2018/6/19.
 */
public interface EsProductRepository extends ElasticsearchRepository<EsProduct, Long> {
    /**
     * Search query
     *
     * @param name              Name of commodity
     * @param subTitle          Commodity Title
     * @param keywords          Commodity keywords
     * @param page              Paging information
     * @return
     */
    Page<EsProduct> findByNameOrSubTitleOrKeywords(String name, String subTitle, String keywords, Pageable page);

}

Add the EsProduct Service interface

package com.macro.mall.tiny.service;

import com.macro.mall.tiny.nosql.elasticsearch.document.EsProduct;
import org.springframework.data.domain.Page;

import java.util.List;

/**
 * Commodity Search Management Service
 * Created by macro on 2018/6/19.
 */
public interface EsProductService {
    /**
     * Import all items from the database to ES
     */
    int importAll();

    /**
     * Delete goods according to id
     */
    void delete(Long id);

    /**
     * Create goods based on id
     */
    EsProduct create(Long id);

    /**
     * Bulk Delete Goods
     */
    void delete(List<Long> ids);

    /**
     * Search for names or subtitles based on keywords
     */
    Page<EsProduct> search(String keyword, Integer pageNum, Integer pageSize);

}

Implementing class EsProduct Service Impl with EsProduct Service interface

package com.macro.mall.tiny.service.impl;

import com.macro.mall.tiny.dao.EsProductDao;
import com.macro.mall.tiny.nosql.elasticsearch.document.EsProduct;
import com.macro.mall.tiny.nosql.elasticsearch.repository.EsProductRepository;
import com.macro.mall.tiny.service.EsProductService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


/**
 * Commodity Search Management Service Implementation Class
 * Created by macro on 2018/6/19.
 */
@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> esProductIterable = productRepository.saveAll(esProductList);
        Iterator<EsProduct> iterator = esProductIterable.iterator();
        int result = 0;
        while (iterator.hasNext()) {
            result++;
            iterator.next();
        }
        return result;
    }

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

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

    @Override
    public void delete(List<Long> ids) {
        if (!CollectionUtils.isEmpty(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);
    }

}

Adding EsProduct Controller Definition Interface

package com.macro.mall.tiny.controller;

import com.macro.mall.tiny.common.api.CommonPage;
import com.macro.mall.tiny.common.api.CommonResult;
import com.macro.mall.tiny.nosql.elasticsearch.document.EsProduct;
import com.macro.mall.tiny.service.EsProductService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * Search Commodity Management Controller
 * Created by macro on 2018/6/19.
 */
@Controller
@Api(tags = "EsProductController", description = "Search Commodity Management")
@RequestMapping("/esProduct")
public class EsProductController {
    @Autowired
    private EsProductService esProductService;

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

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

    @ApiOperation(value = "according to id Bulk Delete Goods")
    @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(value = "according to id Creating Commodities")
    @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);
        } else {
            return CommonResult.failed();
        }
    }

    @ApiOperation(value = "Simple 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 the database into Elastic search


Goods Search


Project source address

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

Public Number

mall project In the whole series of learning courses, we pay attention to the first time acquisition of the public number.

Posted by evo4ever on Sat, 31 Aug 2019 23:08:58 -0700