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 (Collection |
{"bool" : {"must" : {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}} |
NotIn |
findByNameNotIn (Collection |
{"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;
}