需求:如何让ES的某个字段既能支持精确匹配查找,也能支持模糊检索?
方法:将字段的mapping设置为如下这种即可:
"properties": {
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
举个栗子
"properties": {
"name": {
"analyzer": "ik_max_word",
"store": true,
"type": "text"
}
上面这种配置:它只能分词匹配,做不到精确匹配。如我有两条数据
数据1:也无风雨也无晴
数据2:也无风雨也无晴2
搜索:业务风雨也无晴2
正确的结果是只返回数据2,但事实是两条数据它都返回了
怎么样才能让它只返回数据2呢?
再举个栗子
"properties": {
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
上面这种配置,在搜索业务风雨也无晴2的时候将只返回数据2,于是我们就 让字段同时支持精确匹配和模糊检索了。
如果索引已经添加,要更改字段类型映射请看这篇文章,不用写代码,直接postmain就可以了
https://blog.csdn.net/java_xxxx/article/details/108710260
java代码
如果java代码中对字符串按MultiMatchQueryBuilder的方式搜索,并且再添加进入boolTrem里,可以精确匹配,如搜索:“也无风雨也无晴”,结果:“也无风雨也无晴”、“也无风雨也无晴2”、“也啊无啊风啊雨啊也啊无啊晴2”
如果搜索"也无风雨也无晴2",结果:“也无风雨也无晴2”、“也啊无啊风啊雨啊也啊无啊晴2”
如果使用matchPhraseQuery,前提是索引不分词,搜索结果会比上面少了一个““也啊无啊风啊雨啊也啊无啊晴2””,达到精确匹配的效果
postFilterKeyword.should(QueryBuilders.matchPhraseQuery(fileNmae, item));
MultiMatchQueryBuilder query = QueryBuilders.multiMatchQuery(item, locations).type(MultiMatchQueryBuilder.Type.PHRASE).slop(50);
postFilterKeyword.should(query);
public static Page listArticleByEs(Page page, ArticlePub filter){
Integer pageSize = page.getPageSize();
Integer pageNumber = page.getPageNumber();
Short status = filter.getArticleStatus();
Short articleType = filter.getArticleType();
String columnIds = filter.getColumnIds();
Integer roleId = filter.getRoleId();
Integer userType = filter.getUserType();
Long siteId = filter.getArticleSiteId();
Date beginTime = filter.getBeginTime();
Date endTime = filter.getEndTime();
String location = filter.getLocation();
Integer timeType = null == filter.getTimeType() ? 1 : filter.getTimeType();
Integer articleRefNum = filter.getArticleRefNum();
String keyWord = StringUtils.isBlank(filter.getKeyWord()) ? filter.getArticleTitle() : filter.getKeyWord();
pageNumber = null == pageNumber ? 1 : pageNumber;
pageSize = null == pageSize ? 20 : pageSize;
TransportClient client = ESUtils.getClient();
SearchRequestBuilder searchRequestBuilder = client.prepareSearch(ESUtils.articleIndex).setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setTypes("article")
.setFrom((pageNumber - 1) * pageSize).setSize(pageSize);
// 时间查询
if(null != beginTime && null != endTime){
String fileName = timeType.equals(1) ? "sysCreateTime" : "sysModifyTime";
searchRequestBuilder.setPostFilter(QueryBuilders.rangeQuery(fileName).from(dateFormat(beginTime)).to(dateFormat(endTime)).includeLower(true).includeUpper(true));
}
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
BoolQueryBuilder postFilter = QueryBuilders.boolQuery();
// 文章状态
if (null != status) {
postFilter.must(termQuery("articleStatus", status));
}
// 文章类型
if (null != articleType) {
postFilter.must(termQuery("articleType", articleType));
}
// 是否选用
if (null != articleRefNum && articleRefNum == -2) {
postFilter.must(rangeQuery("articleRefNum").gte(1));// 已选用
} else if (null != articleRefNum && articleRefNum == -1) {
postFilter.must(rangeQuery("articleRefNum").lt(1)); // 未选用
}
// 栏目过滤
if (!StringUtils.isBlank(columnIds)) {
// 字符串得到id集合
List<Integer> cids = str2List(columnIds);
postFilter.must(termsQuery("articleColumnId", cids));
} else {
if (userType.equals(1)) { // 站点管理员
postFilter.must(termQuery("articleSiteId", siteId));
} else {
// 站点下有权限的所有栏目
List<Integer> cids = getColumnIdsBySiteId(roleId);
postFilter.must(termsQuery("articleColumnId", cids));
}
}
// 未删除的文章
postFilter.must(termQuery("sysDeleteFlag", 0));
// 关键词查询
String [] locations = handleLocation(location);
if(!StringUtils.isBlank(keyWord)) {
// 多个关键词以|分开表示or
if (keyWord.indexOf("|") != -1) {
BoolQueryBuilder postFilterKeyword = QueryBuilders.boolQuery();
String[] split = keyWord.split("\\|");
for (String item : split) {
if (!StringUtils.isBlank(item)) {
// 查询位置:locations:[articleTitle, articleContetn]
for (String fileNmae : locations) {
postFilterKeyword.should(QueryBuilders.matchPhraseQuery(fileNmae, item));
}
}
}
postFilter.must(postFilterKeyword);
} else if (keyWord.indexOf("&") != -1 ) {
// 多个关键词以&分开作为参数传递过来,表示多个关键词为and的关系
String[] split = keyWord.split("&");
for (String item : split) {
BoolQueryBuilder postFilterKeyword = QueryBuilders.boolQuery();
if (!StringUtils.isBlank(item)) {
// 查询位置:locations:[articleTitle, articleContetn]
for (String fileName : locations) {
postFilterKeyword.should(QueryBuilders.matchPhraseQuery(fileName, item));
}
}
postFilter.must(postFilterKeyword);
}
} else {
// 查询位置:locations:[articleTitle, articleContetn]
BoolQueryBuilder postFilterKeyword = QueryBuilders.boolQuery();
for (String fileName : locations) {
postFilterKeyword.should(QueryBuilders.matchPhraseQuery(fileName, keyWord));
}
postFilter.must(postFilterKeyword);
}
}
if(timeType.equals(1)) {
searchRequestBuilder.addSort(SortBuilders.fieldSort("sysCreateTime").unmappedType("date").order(SortOrder.DESC));
}else{
searchRequestBuilder.addSort(SortBuilders.fieldSort("sysModifyTime").unmappedType("date").order(SortOrder.DESC));
}
boolQueryBuilder.must(postFilter);
searchRequestBuilder.setQuery(boolQueryBuilder);
SearchResponse searchResponse = searchRequestBuilder.get();
SearchHits hits = searchResponse.getHits();
// 得到文章原id
List<Long> ids = new ArrayList<>();
for (SearchHit hit : hits) {
String id = hit.getId();
if (!StringUtils.isBlank(id)) {
ids.add(Long.valueOf(id));
}
}
Page resultPage = new Page();
if (null == ids || 0 == ids.size()) {
resultPage.setTotal(0L);
resultPage.setRows(null);
} else {
List<ArticlePub> articlePubs = listPub(ids, timeType);
resultPage.setTotal(hits.getTotalHits());
resultPage.setRows(articlePubs);
}
return resultPage;
}