抛开原生的操作,这里我们采用spring提供的框架进行操作,会是操作方便不少。
maven引用
<spring-data-elasticsearch.version>2.0.6.RELEASE</spring-data-elasticsearch.version>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>${spring-data-elasticsearch.version}</version>
<exclusions>
<exclusion>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
</exclusion>
</exclusions>
</dependency>
通用类:
public class BaseESDaoImpl<T, ID extends Serializable> extends AbstractElasticsearchRepository<T, ID> implements BaseESDao<T, ID> {
public BaseESDaoImpl() {
super();
}
public BaseESDaoImpl(ElasticsearchEntityInformation<T, ID> metadata, ElasticsearchOperations elasticsearchOperations) {
super(metadata, elasticsearchOperations);
}
public BaseESDaoImpl(ElasticsearchOperations elasticsearchOperations) {
super(elasticsearchOperations);
}
@Override
protected String stringIdRepresentation(ID id) {
return id.toString();
}
}
实体类:
@Document(indexName = "dcang", type = "hot_word_es")
public class HotWordEs {
@Id
private Long id;
/**
* 搜索类型
*/
@Field(type = FieldType.String)
private SearchType searchType;
/**
* 搜索关键字,这里用了分词器
*/
@Field(type = FieldType.String, analyzer = "ik_max_word", searchAnalyzer=ik_max_word")
//String 被转成 text, auto 被转成 keyword
private String keyword;
/**
* 搜索人ID
*/
@Field(type = FieldType.Long)
private Long memberId;
Dao:
public interface HotWordEsDao extends BaseESDao<HotWordEs, Long>, HotWordEsDaoPlus {}
DaoPlus,相当于dao接口,如:
public interface HotWordEsDaoPlus {
/**
* 查询热门词汇
*
* @param searchType 词汇类型
* @param size 查询个数
* @return 返回结果
*/
List<String> searchHotWordEs(SearchType searchType, Integer size);
}
基础的环境搭建,我就是简单的介绍下。重点来了,我们看接下来的实例:
搜索条件:
实体类 :
AssociationLotEs 记录了拍品的出价次数和围观人数
LotEs: 拍品
MemberEs: 会员(拍品发布者)
//根据围观数和竞价次数,得出分值
ScoreFunctionBuilder scoreFunctionBuilder = new ScriptScoreFunctionBuilder(new Script("return doc['observerCount'].value + doc['bidPriceCount'].value"));
//查询条件,最大出价大于4000的拍品
RangeQueryBuilder maxAmount = rangeQuery("maxAmount").gte(4000);
FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(maxAmount, scoreFunctionBuilder)
.scoreMode(FiltersFunctionScoreQuery.ScoreMode.SUM); //函数得出的分值与原始分值相加
//关联子文档查询
QueryBuilder child = QueryBuilders.hasChildQuery("association_lot_es", functionScoreQueryBuilder, ScoreMode.Total);
//必须是满足条件的店铺
BoolQueryBuilder parent = QueryBuilders.boolQuery();
//这里不计入分值,仅为做满足条件的查询
parent.must(termQuery("certification", "true").boost(0))
.must(termQuery("dispute", "true").boost(0))
.must(rangeQuery("shopLevel").gte(3).boost(0))
.must(rangeQuery("shopScore").gte(4.7).boost(0));
//关联父文档查询
HasParentQueryBuilder post_es_parent = QueryBuilders.hasParentQuery("member_es", parent, true);
//第一个查询条件生成
BoolQueryBuilder bb2 = QueryBuilders.boolQuery();
BoolQueryBuilder queryBuilder2 = bb2.must(post_es_parent).must(child);
//为人工干预的查询增加人气打分,仅作为打分
ScoreFunctionBuilder scoreFunctionBuilder2 = new ScriptScoreFunctionBuilder(new Script("return doc['observerCount'].value + doc['bidPriceCount'].value"));
FunctionScoreQueryBuilder functionScoreQueryBuilder2 = QueryBuilders.functionScoreQuery(scoreFunctionBuilder2).scoreMode(FiltersFunctionScoreQ uery.ScoreMode.SUM);
QueryBuilder child2 = QueryBuilders.hasChildQuery("association_lot_es", functionScoreQueryBuilder2, ScoreMode.Total);
BoolQueryBuilder bb4 = QueryBuilders.boolQuery();
//赋予人工干预的拍品分值,并组成查询条件
bb4.must(termQuery("artificial", true).boost(0)).should(child2);
BoolQueryBuilder bb3 = QueryBuilders.boolQuery();
//组合出完整的查询语句
bb3.should(queryBuilder2).should(bb4);
//根据结束时间计算出相应的分值,时间默认分值是时间戳,实际应用中得归一化
ScoreFunctionBuilder scoreFunctionBuilder3 = new ScriptScoreFunctionBuilder(new Script("return doc['endTime'].value "));
//查询语句
FunctionScoreQueryBuilder functionScoreQueryBuilder3 = QueryBuilders.functionScoreQuery(bb3, scoreFunctionBuilder3)
.boostMode(CombineFunction.SUM);//得分相加
Page< LotEs > search = lotEsDao.search(functionScoreQueryBuilder3, new PageRequest(0, 10));
注意事项:
超代关系的文档,必须在同一分片上。所以routing必须保持一致,不然查询结果会出错