I. Main contents

  • Spring Boot introduces Elasticsearch
  • The use of ElasticsearchTemplate
  • The use of ElasticsearchRepository

Second, environmental integration

Create Elasticsearch project and import dependencies

Typically, a separate project is created to operate on ES.

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> The < version > 2.5.1 < / version > < / dependency >Copy the code

Unified version

Springboot-data-elasticsearch is currently available in version 2.5.1, which uses ES version 7.12.1. Note that springboot-data-ElasticSearch must be the same as the server version installed.

Can see through the Maven repository version information, address: mvnrepository.com/artifact/or…

Modifying a Configuration File

spring: 
 data: 
  elasticsearch: 
   cluster-name: es-cluster
   cluster-nodes: 10.13328.55.: 9300
Copy the code

ElasticsearchTemplate (

ElasticsearchTemplate is similar to RedisTemplate, and is a lower-level Elasticserch class provided by Spring that interacts with Elasticserch.

Commonly used annotations

@Document

Annotations apply to classes, marking the entity class as a document object and specifying the relationship between the entity class and the index. Common configuration items are as follows:

  • IndexName: indicates the indexName
  • Type: indicates the index type. The default value is empty
  • Shards: number of master shards. Default: 5
  • Replicas: indicates the number of replication fragments. The default value is 1
  • CreateIndex: creates an index. Default is true

@Id

Specify the document ID and, with this annotation, the document ID will be the same as our data ID, otherwise es will be created automatically without a default value.

@Field

Specify a common property that indicates that this is a field in the document. Common configuration items are as follows:

  • Type: indicates the attribute type of Elasticsearch. Automatic detection by default. The FiledType enumeration is a quick way to get this
public enum FieldType {
	Text,// The character type that will be split and indexed
	Integer,
	Long,
	Date,
	Float,
	Double,
	Boolean,
	Object,
	Auto,// Automatically determine the field type
	Nested,// Nested object types
	Ip,
	Attachment,
	Keyword// The type of index that will not be segmented
}
Copy the code
  • Index: Indicates whether to create an inverted index. Generally, attributes that do not require word segmentation do not need to create an index

  • Analyzer: Specifies the index type.

  • Store: Indicates whether the storage is enabled. By default, the storage is disabled.

    Elasticsearch stores this Field in the Field regardless of whether we set store to true or false; But what’s the difference?

    1. Store = false, default; The given Field is stored only in the “_source” Field;

    2. When store = true, the value of the Field is stored in a separate Field at the same level as _source. It’s also stored in _source, so there are two copies.

    So in what business scenarios do we use store Field functionality?

    1. The _source field is disabled in index mapping. In this case, if a field is not defined as store=true, it will not be visible in the returned query results.
    2. The content of _source is very large. If we want to interpret a field value in the returned _source document, it can be very expensive (of course, you can also define Source Filtering to reduce network overhead), rather than storing a book in a document. So document might have these fields: title, date, content. If we only want to query the title and date information of the book, and do not need to interpret the entire _source (which is very large), we can consider setting the title and date fields to store=true.

Create the entity

// The associated index is item, of type _doc, used directly without creating the index
@Document(indexName = "item",type = "_doc",createIndex = "false")
public class Item {
    @Id
    private Long id;
    // title uses ik for participles
    @Field(type = FieldType.Text,analyzer = "ik_max_word")
    private String title;
    // brand is not segmented
    @Field(type=FieldType.Keyword)
    private String brand;
    @Field(type=FieldType.Double)
    private Double price;
    // Brand is not segmented and no index is created
    @Field(index = false,type = FieldType.Keyword)
    private String images;
}
Copy the code

The index management

The ElasticsearchTemplate provides methods for creating indexes, but it is not recommended to use the ElasticsearchTemplate to manage indexes (create indexes, update mappings, drop indexes).

An index is like a database or a table in a database. We do not frequently create, modify and delete information about a database or table through Java code. We only perform CRUD operations on data.

// Create index
elasticsearchTemplate.createIndex(Class<T> clazz);
// Delete index, there are several methods, interested students can browse source code
elasticsearchTemplate.deleteIndex(Class<T> clazz);
Copy the code

Create a document

A single document is added

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class ESTest {
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;
    @Test
    public void insertItemDoc(a){
        Item item = new Item(1001L."XXX1"."XXX1"."XXX1");
        IndexQuery indexQuery = newIndexQueryBuilder().withObject(item).build(); elasticsearchTemplate.index(indexQuery); }}Copy the code

Batch Adding Documents

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class ESTest {
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;
    @Test
    public void insertItemDocBulk(a) {
    	List<Item> list = new ArrayList<>();
        list.add(new IndexQueryBuilder().withObject(new Item(1001L."XXX1"."XXX1"."XXX1")).build())
        list.add(new IndexQueryBuilder().withObject(new Item(1002L."XXX2"."XXX2"."XXX2")).build())
        IndexQuery indexQuery = newIndexQueryBuilder().withObject(item).build(); elasticsearchTemplate.index(indexQuery); }}Copy the code

Delete the document

Deletions are based on primary keys and provide two methods:

  • delete(String indexName,String typeName,String id); Specify the index, type, and ID value by string;
  • Delete (Class,String id) The first parameter passes the entity Class Class type. This method is recommended to reduce the probability that the index name and type name will be incorrect due to manual writing.

The code is relatively simple, no example.

Modify the document

@Test
public void updateItemDoc(a) {
    Map<String, Object> sourceMap = new HashMap<>();
    sourceMap.put("title"."YYY");

    IndexRequest indexRequest = new IndexRequest();
    indexRequest.source(sourceMap);

    UpdateQuery updateQuery = new UpdateQueryBuilder()
        .withClass(Stu.class)
        .withId("1001")
        .withIndexRequest(indexRequest)
        .build();
    elasticsearchTemplate.update(updateQuery);
}
Copy the code

Query the document

Fuzzy query

Use the query condition to match all the fields to query

Does it look strange to some of the entries? It feels big, doesn’t it? Hold on. There’s an explanation at the end.

@Test
public void queryItemDoc(a) {
    // The boy matches all the fields
    QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders.queryStringQuery("Young");
    SearchQuery is an interface that can only instantiate the implementation class.
    SearchQuery searchQuery = new NativeSearchQuery(queryStringQueryBuilder);
    List<Item> list = elasticsearchTemplate.queryForList(searchQuery, Item.class);
    for(Item item : list){ System.out.println(item); }}Copy the code

Query all documents with match_all

@Test
public void matchAllItemDoc(a) {
   SearchQuery searchQuery = new NativeSearchQuery(QueryBuilders.matchAllQuery());
    List<Item> list = elasticsearchTemplate.queryForList(searchQuery, Item.class);
    for(Item item : list){ System.out.println(item); }}Copy the code

Use match to query and sort paging documents

@Test
public void matchItemDoc(a) {
    // Construct the page information: the first argument is the page number, counted from 0. The second parameter is the number of columns to display per page
   	Pageable pageable = PageRequest.of(0.2);
    // Construct sort information
    SortBuilder sortBuilder = new FieldSortBuilder("price")
                .order(SortOrder.DESC);
    SearchQuery query = new NativeSearchQueryBuilder()
        .withQuery(QueryBuilders.matchQuery("title"."english"))
        .withPageable(pageable)
        .withSort(sortBuilder)
        .build();
    AggregatedPage<Item> pagedItem = elasticsearchTemplate.queryForPage(query, Item.class);
    System.out.println("The total number of pages after query is:" + pagedItem.getTotalPages());
    List<Item> list = pagedItem.getContent();
    for(Item item : list) { System.out.println(item); }}Copy the code

Multi-condition query

 @Test
 public void mustShouldItemDoc(a){
     BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
     List<QueryBuilder> listQuery = new ArrayList<>();
     listQuery.add(QueryBuilders.matchPhraseQuery("title"."XX"));
     listQuery.add(QueryBuilders.rangeQuery("price").gte(10).lte(100));
     //boolQueryBuilder.should().addAll(listQuery); / / logical or
     boolQueryBuilder.must().addAll(listQuery);  / / logic
     SearchQuery searchQuery = new NativeSearchQuery(boolQueryBuilder);
     List<Item> list = elasticsearchTemplate.queryForList(searchQuery, Item.class);
     for(Item item : list){ System.out.println(item); }}Copy the code

Highlighting the query

@Test
public void highlightStuDoc(a){
    // Specify what label to wrap the highlighted information with. Default: 
    String preTag = "<font color='red'>";
    String postTag = "</font>";

    Pageable pageable = PageRequest.of(0.10);

    SortBuilder sortBuilder = new FieldSortBuilder("price")
        .order(SortOrder.DESC);
	// construct the query rule
    SearchQuery query = new NativeSearchQueryBuilder()
        .withQuery(QueryBuilders.matchQuery("title"."XXX"))
        .withHighlightFields(new HighlightBuilder.Field("title")
                             .preTags(preTag)
                             .postTags(postTag))
        .withSort(sortBuilder)
        .withPageable(pageable)
        .build();
    AggregatedPage<Item> paged = esTemplate.queryForPage(query, Item.class, new SearchResultMapper() {
        @Override
        public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
			// Define a list to hold the final data returned
            List<Item> listHighlight = new ArrayList<>();
			// Retrieve the hit information
            SearchHits hits = response.getHits();
            for (SearchHit h : hits) {
                // Retrieve highlighted data
                HighlightField highlightField = h.getHighlightFields().get("title");
                String title = highlightField.getFragments()[0].toString();
				// Retrieve other data
                Object id = (Object)h.getSourceAsMap().get("id");
                String brand = (String)h.getSourceAsMap().get("brand");
                Object price = (Object)h.getSourceAsMap().get("price");
                String images = (String)h.getSourceAsMap().get("images");
				// Process data
                Item itemHL = new Item();
                item.setId(Long.valueOf(id.toString()));
                item.setTitle(title);
                item.setBrand(brand);
                item.setPrice(Double.valueof(price.toString));
                item.setImages(images);

                listHighlight.add(itemHL);
            }

            if (listHighlight.size() > 0) {
                return new AggregatedPageImpl<>((List<T>)listHighlight);
            }
            return null; }}); System.out.println("The total number of pages after query is:" + paged.getTotalPages());
    List<Item> list = paged.getContent();
    for(Item item : list) { System.out.println(item); }}Copy the code

ElasticsearchRepository

ElasticsearchRepository is an interface to manipulate Elasticsearch based on ElasticsearchTemplate.

What did it mainly do? What can we do with it?

  • It mainly helps us to encapsulate some common methods. The diagram below:

  • We can also create queries automatically by using keywords such as Not Add Like Or Between. It will do it for you automatically, no need to write an implementation class.

    For example, if your method name is: findByTitle, it knows that you are querying by title and automatically does it for you without writing an implementation class.

    [Custom method naming convention] :

Custom Repository interface

This is in accordance with the Specification of SpringData, in the custom interface directly specify the name of the query method can be queried, without implementation. In idea, it will also prompt some fields in ES, which is quite convenient to write.

/** * need to inherit ElasticsearchRepository interface */
public interface ItemRepository extends ElasticsearchRepository<Item.Long> {
    /** * Method names must comply with SpringData's specification * price range queries */
    List<Item> findByPriceBetween(double price1, double price2);
}
Copy the code

Create a document

A single document is added

You can call the Save () method of ItemRepository directly.

@Autowired
private ItemRepository itemRepository;
@Test
public void insert(a){
    Item item = new Item(1L.Mi Phone 7."Millet".3499.00."http://xxx/xxx.jpg");
    itemRepository.save(item);
}
Copy the code

Batch Adding Documents

Insert multiple document data using the saveAll() method

@Autowired
private ItemRepository itemRepository;
@Test
public void indexList(a) {
    List<Item> list = new ArrayList<>();
    list.add(new Item(1L.Mi Phone 7."Millet".3299.00."http://xxx/1.jpg"));
    list.add(new Item(2L."Nut Phone R1"."The hammer".3699.00."http://xxx/1.jpg"));
    list.add(new Item(3L."Huawei META10"."Huawei".4499.00."http://xxx/1.jpg"));
    list.add(new Item(4L."Millet Mix2S"."Millet".4299.00."http://xxx/1.jpg"));
    list.add(new Item(5L."Glory V10"."Huawei".2799.00."http://xxx/1.jpg"));
    // Accept object set to achieve batch add
    itemRepository.saveAll(list);
}
Copy the code

Modify the document

The document data is also modified using the save() method.

Query Parameters

ElasticsearchRepository provides special search() methods for building queries. The main parameters in these methods are SearchQuery and QueryBuilder, so the main parameters to complete some special queries are these two parameters.

SearchQuery

Through the source code we can see that SearchQuery is an interface, there is an implementation class called NativeSearchQuery, in actual use, our main task is to build NativeSearchQuery to complete some complex queries.

We can see that the main input parameters for Creative SearchQuery are QueryBuilder, SortBuilder, and HighlightBuilder

In general, instead of being new Creative SearchQuery directly, we use creative SearchQueryBuilder to build creative SearchQuery.

NativeSearchQueryBuilder		
    .withQuery(QueryBuilder1)
    .withFilter(QueryBuilder2)
    .withSort(SortBuilder1)
    .withXXXX()
    .build();
Copy the code

QueryBuilder

QueryBuilder is an interface that has a large number of implementation classes that can be used to build different query criteria.

To build QueryBuilder, we can use the utility class QueryBuilders, which has a large number of methods to build various QueryBuilders, string, Boolean, match, geographic range, and so on.

// Build a normal query
SearchQuery searchQuery = new NativeSearchQueryBuilder()
    .withQuery(QueryBuilders.queryStringQuery("Spring Boot OR Books"))
    .build();
Copy the code

The query method is similar to that of ElasticsearchTemplate.

ElasticsearchRepository can be used in normal query scenarios, and the ElasticsearchRepository template can be used in complex query scenarios.

Finally, welcome to “Hugh’s Whiteboard” public number, private letter I learn together, grow together! Finally, if it helps you a little bit, can you give a thumbs up? Thank you very much