springboot操作ES

springboot操作ES

ES中文档的id是字符串类型,因此实体类的id必须为string类型

一、简单的查询

repository接口中提供了一些简单的查询方法,包括:

添加或更新一条文档:save(T t) 当id不存在时添加,存在时更新

删除一条记录:delete(T t) 根据实体类对象的id删除

查询所有:findAll()

查询一个:findById(String id)

排序查询:findAll(Sort.by(Sort.Order.asc(“字段名”)));

自定义基本的查询 :自定义方法名的格式为findBy…

Keyword Sample Elasticsearch Query String
And findByNameAndPrice {"bool" : {"must" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}}
Or findByNameOrPrice {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}}
Is findByName {"bool" : {"must" : {"field" : {"name" : "?"}}}}
Not findByNameNot {"bool" : {"must_not" : {"field" : {"name" : "?"}}}}
Between findByPriceBetween {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}
LessThanEqual findByPriceLessThan {"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}
GreaterThanEqual findByPriceGreaterThan {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}
Before findByPriceBefore {"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}
After findByPriceAfter {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}
Like findByNameLike {"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}
StartingWith findByNameStartingWith {"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}
EndingWith findByNameEndingWith {"bool" : {"must" : {"field" : {"name" : {"query" : "*?","analyze_wildcard" : true}}}}}
Contains/Containing findByNameContaining {"bool" : {"must" : {"field" : {"name" : {"query" : "**?**","analyze_wildcard" : true}}}}}
In findByNameIn
(Collectionnames)
{"bool" : {"must" : {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}}
NotIn findByNameNotIn
(Collectionnames)
{"bool" : {"must_not" : {"bool" : {"should" : {"field" : {"name" : "?"}}}}}}
Near findByStoreNear Not Supported Yet !
True findByAvailableTrue {"bool" : {"must" : {"field" : {"available" : true}}}}
False findByAvailableFalse {"bool" : {"must" : {"field" : {"available" : false}}}}
OrderBy findByAvailable
TrueOrderByNameDesc
{"sort" : [{ "name" : {"order" : "desc"} }],"bool" : {"must" : {"field" : {"available" : true}}}}

步骤:

1.创建实体类并映射

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
@Document(indexName = "supplier_index",type = "supplier")
public class Supplier implements Serializable {
    @Id   //映射id
    private String id;
    @Field(type = FieldType.Keyword)   //映射字段,可以指定分词
    private String name;
    @Field(type = FieldType.Keyword)
    private String leader;
    @Field(type = FieldType.Keyword)
    private String phone;
    @Field(type = FieldType.Date)
    private Date create_date;
}

2.创建dao

public interface SupplierRepository  extends ElasticsearchRepository<Supplier,String> {
    //如果需要自定义基本的查询在这里书写
    //根据name查询
    List<Supplier> findByName(String keyWord);
    //根据name和leader查询
    List<Supplier> findByNameAndLeader(String key1,String key2);
    List<Supplier> findByNameOrLeader(String key1,String key2);
}

3.配置application.yml

spring:
  #配置es  注意es在浏览器中的端口号为9200,在java中为9300
  data:
    elasticsearch:
      cluster-nodes: 192.168.116.135:9300

4.使用es

@SpringBootTest
@RunWith(SpringRunner.class)
public class TestEs {
    @Autowired
    private SupplierRepository supplierRepository;
    @Test
    public void test(){
        //查询所有
        supplierRepository.findAll().forEach(supplier -> System.out.println(supplier));
        //根据id查询
        System.out.println(supplierRepository.findById("1016"));
        //排序查询
        supplierRepository.findAll(Sort.by(Sort.Order.asc("name"))).forEach(supplier -> System.out.println(supplier));
        //根据name查询
        System.out.println(supplierRepository.findByName("腾讯"));
        //根据name和leader查询
        System.out.println(supplierRepository.findByNameAndLeader("腾讯","马化腾"));
        //根据name或者leader查询
        System.out.println(supplierRepository.findByNameOrLeader("0001","马化腾"));
    }
}

二、复杂的查询

对于分页,高亮、组合灯复杂的查询需要自定义接口并实现

步骤:

1.创建实体类并映射

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
@Document(indexName = "supplier_index",type = "supplier")
public class Supplier implements Serializable {
    @Id   //映射id
    private String id;
    @Field(type = FieldType.Keyword)   //映射字段,可以指定分词
    private String name;
    @Field(type = FieldType.Keyword)
    private String leader;
    @Field(type = FieldType.Keyword)
    private String phone;
    @Field(type = FieldType.Date)
    private Date create_date;
}

2.新的包中创建自定义接口

package com.baizhi.es;
import com.baizhi.entity.Supplier;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository  //交给工厂管理
public interface SupplierRepository1 {
    //term查询
    List<Supplier> findByNameTerm(String name);
    //分页查询
    List<Supplier> findByPageable(int page, int size);
    //模糊查询,高亮,分页
    List<Supplier> findByNameAndHighlightAndPageable(String key,
                                                     int page,
                                                     int size);
}

3.实现自定义的接口

package com.baizhi.es;

import com.baizhi.entity.Supplier;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;

@Configuration
public class SupplierRepositoryImpl1 implements SupplierRepository1 {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Override
    public List<Supplier> findByNameTerm(String name) {
        //创建query对象
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder().withQuery(termQuery("name", name));
        //执行查询
        List<Supplier> suppliers = elasticsearchTemplate.queryForList((SearchQuery) queryBuilder, Supplier.class);
        return suppliers;
    }

    @Override
    public List<Supplier> findByPageable(int page, int size) {
        return null;
    }

    //高亮查询的实现
    @Override
    public List<Supplier> findByNameAndHighlightAndPageable(String name, int page, int size) {
        //高亮查询设置
        HighlightBuilder.Field nameField = new HighlightBuilder
                .Field("*")
                .preTags("")
                .postTags("").requireFieldMatch(false);
        //创建query对象
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.multiMatchQuery(name,"name","leader"))
                .withPageable(PageRequest.of(page,size))
                .withHighlightFields(nameField)
                .build();
        //执行查询 参数1 query对象 参数2 要映射的类  参数3  查询结果的重新映射
        AggregatedPage<Supplier> suppliers = elasticsearchTemplate.queryForPage(nativeSearchQuery, Supplier.class, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
                //获取查询的结果
                SearchHits searchHits = response.getHits();
                SearchHit[] hits = searchHits.getHits();
                //遍历创建集合
                ArrayList<Supplier> suppliers = new ArrayList<>();
                for (SearchHit hit : hits) {
                    //原始的查询结果
                    Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                    //获取各个字段并创建新的对象
                    Supplier supplier = new Supplier();
                    supplier.setId(sourceAsMap.get("id").toString());
                    supplier.setName(sourceAsMap.get("name").toString());
                    supplier.setLeader(sourceAsMap.get("leader").toString());
                    supplier.setPhone(sourceAsMap.get("phone").toString());
                    long create_date = Long.parseLong(sourceAsMap.get("create_date").toString());
                    supplier.setCreate_date(new Date(create_date));
                    //高亮的处理
                    Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                    System.out.println(highlightFields);
                    if (highlightFields.get("name") != null) {
                        String nameHighlight = highlightFields.get("name").getFragments()[0].toString();
                        supplier.setName(nameHighlight);
                    }
                    if (highlightFields.get("leader") != null) {
                        String leaderHighlight = highlightFields.get("leader").getFragments()[0].toString();
                        supplier.setLeader(leaderHighlight);
                    }
                    suppliers.add(supplier);
                }
                return new AggregatedPageImpl<T>((List<T>)suppliers);
            }
        });
        return suppliers.getContent();
    }
}

三、注意事项

es分页查询中page从0开始,因此在结合jqGrid使用时要page–

@RequestMapping("esShowByPage")
    public Map<String,Object> esShowAll(Integer page,Integer rows){
        page--;
        //查询当前页内容
        List<Supplier> suppliers = supplierService.esShowByPage(page, rows);
        //获取总页数
        int size = supplierService.esShowAll().size();
        //获取总条数
        Integer total = (size%rows==0)?(size/rows):(size/rows+1);
        HashMap<String, Object> map = new HashMap<>();

        map.put("rows",suppliers);
        map.put("page",page);
        map.put("total",total);
        map.put("records",size);
        return map;
    }
@RequestMapping("esSearchByPage")
    public Map<String,Object> esSearchByPage(String keyWords,Integer page,Integer rows){
        page--;
        //获取当前页查询的内容
        List<Supplier> suppliers = supplierService.serachByPage(keyWords, page, rows);
        //获取查询的总条数
        int size = supplierService.searchAll(keyWords).size();
        //获取查询的总页数
        Integer total = (size%rows==0)?(size/rows):(size/rows+1);
        HashMap<String, Object> map = new HashMap<>();

        map.put("rows",suppliers);
        map.put("page",page);
        map.put("total",total);
        map.put("records",size);
        return map;
    }

你可能感兴趣的:(学习笔记)