org.elasticsearch.index.query.MultiMatchQueryBuilder Java Examples

The following examples show how to use org.elasticsearch.index.query.MultiMatchQueryBuilder. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: MatchPredicate.java    From Elasticsearch with Apache License 2.0 6 votes vote down vote up
public static String getMatchType(@Nullable  String matchType, DataType columnType) {
    if (matchType == null) {
        return defaultMatchType(columnType);
    }
    if (columnType.equals(DataTypes.STRING)) {
        try {
            MultiMatchQueryBuilder.Type.parse(matchType, ParseFieldMatcher.STRICT);
            return matchType;
        } catch (ElasticsearchParseException e) {
            throw new IllegalArgumentException(String.format(Locale.ENGLISH,
                    "invalid MATCH type '%s' for type '%s'", matchType, columnType), e);
        }
    } else if (columnType.equals(DataTypes.GEO_SHAPE)) {
        if (!SUPPORTED_GEO_MATCH_TYPES.contains(matchType)) {
            throw new IllegalArgumentException(String.format(Locale.ENGLISH,
                    "invalid MATCH type '%s' for type '%s', valid types are: [%s]",
                    matchType, columnType, Joiner.on(",").join(SUPPORTED_GEO_MATCH_TYPES)));
        }
        return matchType;
    }
    throw new IllegalArgumentException("No match type for dataType: " + columnType);
}
 
Example #2
Source File: OptionParser.java    From Elasticsearch with Apache License 2.0 6 votes vote down vote up
private static void raiseIllegalOptions(MultiMatchQueryBuilder.Type matchType, Map options) {
    List<String> unknownOptions = new ArrayList<>();
    List<String> invalidOptions = new ArrayList<>();
    for (Object o : options.keySet()) {
        assert o instanceof String;
        if (!SUPPORTED_OPTIONS.contains(o)) {
            unknownOptions.add((String) o);
        } else {
            invalidOptions.add((String) o);
        }
    }
    if (!unknownOptions.isEmpty()) {
        throw new IllegalArgumentException(String.format(Locale.ENGLISH,
                "match predicate doesn't support any of the given options: %s",
                Joiner.on(", ").join(unknownOptions)));
    } else {
        throw new IllegalArgumentException(String.format(Locale.ENGLISH,
                "match predicate option(s) \"%s\" cannot be used with matchType \"%s\"",
                Joiner.on(", ").join(invalidOptions),
                matchType.name().toLowerCase(Locale.ENGLISH)
        ));
    }
}
 
Example #3
Source File: MatchQueryBuilder.java    From Elasticsearch with Apache License 2.0 6 votes vote down vote up
public MatchQueryBuilder(MapperService mapperService,
                         IndexCache indexCache,
                         @Nullable BytesRef matchType,
                         @Nullable Map options) throws IOException {
    this.mapperService = mapperService;
    this.indexCache = indexCache;
    if (matchType == null) {
        this.matchType = MultiMatchQueryBuilder.Type.BEST_FIELDS;
    } else {
        this.matchType = SUPPORTED_TYPES.get(matchType);
        if (this.matchType == null) {
            throw illegalMatchType(BytesRefs.toString(matchType));
        }
    }
    this.options = OptionParser.parse(this.matchType, options);
}
 
Example #4
Source File: MultiMatchQuery.java    From Elasticsearch with Apache License 2.0 6 votes vote down vote up
public Query parse(MultiMatchQueryBuilder.Type type, Map<String, Float> fieldNames, Object value, String minimumShouldMatch) throws IOException {
    if (fieldNames.size() == 1) {
        Map.Entry<String, Float> fieldBoost = fieldNames.entrySet().iterator().next();
        Float boostValue = fieldBoost.getValue();
        return parseAndApply(type.matchQueryType(), fieldBoost.getKey(), value, minimumShouldMatch, boostValue);
    }

    final float tieBreaker = groupTieBreaker == null ? type.tieBreaker() : groupTieBreaker;
    switch (type) {
        case PHRASE:
        case PHRASE_PREFIX:
        case BEST_FIELDS:
        case MOST_FIELDS:
            queryBuilder = new QueryBuilder(tieBreaker);
            break;
        case CROSS_FIELDS:
            queryBuilder = new CrossFieldsQueryBuilder(tieBreaker);
            break;
        default:
            throw new IllegalStateException("No such type: " + type);
    }
    final List<? extends Query> queries = queryBuilder.buildGroupedQueries(type, fieldNames, value, minimumShouldMatch);
    return queryBuilder.combineGrouped(queries);
}
 
Example #5
Source File: MultiMatchQuery.java    From Elasticsearch with Apache License 2.0 5 votes vote down vote up
public List<Query> buildGroupedQueries(MultiMatchQueryBuilder.Type type, Map<String, Float> fieldNames, Object value, String minimumShouldMatch) throws IOException{
    List<Query> queries = new ArrayList<>();
    for (String fieldName : fieldNames.keySet()) {
        Float boostValue = fieldNames.get(fieldName);
        Query query = parseGroup(type.matchQueryType(), fieldName, boostValue, value, minimumShouldMatch);
        if (query != null) {
            queries.add(query);
        }
    }
    return queries;
}
 
Example #6
Source File: ElasticSearchQueryManualTest.java    From tutorials with MIT License 5 votes vote down vote up
@Test
public void givenMultimatchQuery_whenDoSearch_thenAllProvidedFieldsMatch() {
    final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(multiMatchQuery("tutorial").field("title")
        .field("tags")
        .type(MultiMatchQueryBuilder.Type.BEST_FIELDS))
        .build();

    final SearchHits<Article> articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog"));

    assertEquals(2, articles.getTotalHits());
}
 
Example #7
Source File: Paramer.java    From elasticsearch-sql with Apache License 2.0 5 votes vote down vote up
public static ToXContent fullParamer(MultiMatchQueryBuilder query, Paramer paramer) {
    if (paramer.analysis != null) {
        query.analyzer(paramer.analysis);
    }

    if (paramer.boost != null) {
        query.boost(paramer.boost);
    }

    if (paramer.slop != null) {
        query.slop(paramer.slop);
    }

    if (paramer.type != null) {
        query.type(paramer.type);
    }

    if (paramer.tieBreaker != null) {
        query.tieBreaker(paramer.tieBreaker);
    }

    if (paramer.operator != null) {
        query.operator(paramer.operator);
    }

    if (paramer.minimumShouldMatch != null) {
        query.minimumShouldMatch(paramer.minimumShouldMatch);
    }

    query.fields(paramer.fieldsBoosts);

    return query;
}
 
Example #8
Source File: Paramer.java    From elasticsearch-sql with Apache License 2.0 5 votes vote down vote up
public static ToXContent fullParamer(QueryStringQueryBuilder query, Paramer paramer) {
    if (paramer.analysis != null) {
        query.analyzer(paramer.analysis);
    }

    if (paramer.boost != null) {
        query.boost(paramer.boost);
    }

    if (paramer.slop != null) {
        query.phraseSlop(paramer.slop);
    }

    if (paramer.defaultField != null) {
        query.defaultField(paramer.defaultField);
    }

    if (paramer.tieBreaker != null) {
        query.tieBreaker(paramer.tieBreaker);
    }

    if (paramer.operator != null) {
        query.defaultOperator(paramer.operator);
    }

    if (paramer.type != null) {
        query.type(MultiMatchQueryBuilder.Type.parse(paramer.type.toLowerCase(Locale.ROOT), LoggingDeprecationHandler.INSTANCE));
    }

    if (paramer.minimumShouldMatch != null) {
        query.minimumShouldMatch(paramer.minimumShouldMatch);
    }

    query.fields(paramer.fieldsBoosts);

    return query;
}
 
Example #9
Source File: IndexSearchDaoImpl.java    From herd with Apache License 2.0 5 votes vote down vote up
/**
 * Private method to build a multimatch query based on a given set of fields and boost values in json format
 *
 * @param multiMatchQueryBuilder A {@link MultiMatchQueryBuilder} which should be constructed
 * @param fieldsBoostsJsonString A json formatted String which contains individual fields and their boost values
 * @param match the set of match fields that are to be searched upon in the index search
 */
private void buildMultiMatchQueryWithBoosts(MultiMatchQueryBuilder multiMatchQueryBuilder, String fieldsBoostsJsonString, Set<String> match)
{
    try
    {
        @SuppressWarnings("unchecked")
        final Map<String, String> fieldsBoostsMap = jsonHelper.unmarshallJsonToObject(Map.class, fieldsBoostsJsonString);

        // This additional step is needed because trying to cast an unmarshalled json to a Map of anything other than String key-value pairs won't work
        final Map<String, Float> fieldsBoosts = new HashMap<>();

        // If the match column is included
        if (match != null && match.contains(MATCH_COLUMN))
        {
            // Add only the column.name and schemaColumn.name fields to the fieldsBoosts map
            fieldsBoostsMap.forEach((field, boostValue) ->
            {
                if (field.contains(COLUMNS_NAME_FIELD) || field.contains(SCHEMA_COLUMNS_NAME_FIELD))
                {
                    fieldsBoosts.put(field, Float.parseFloat(boostValue));
                }
            });
        }
        else
        {
            fieldsBoostsMap.forEach((field, boostValue) -> fieldsBoosts.put(field, Float.parseFloat(boostValue)));
        }

        // Set the fields and their respective boosts to the multi-match query
        multiMatchQueryBuilder.fields(fieldsBoosts);
    }
    catch (IOException e)
    {
        LOGGER.warn("Could not parse the configured JSON value for ngrams fields: {}", ConfigurationValue.ELASTICSEARCH_SEARCHABLE_FIELDS_NGRAMS, e);
    }
}
 
Example #10
Source File: MultiMatchQueryDemo.java    From elasticsearch-full with Apache License 2.0 5 votes vote down vote up
@Test
public void testForClient() throws Exception {

    /**
     * @see <a href='https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-multi-match-query.html'></a>
     * MultiMatchQuery依赖于match query ,也就是其核心是基于MatchQuery构建的
     *
     */

    MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("elasticsearch match query","title", "descrption");

    multiMatchQueryBuilder.analyzer("standard");
    multiMatchQueryBuilder.cutoffFrequency(0.001f);
    multiMatchQueryBuilder.field("title",20);
    multiMatchQueryBuilder.fuzziness(Fuzziness.TWO);
    multiMatchQueryBuilder.maxExpansions(100);
    multiMatchQueryBuilder.prefixLength(10);
    multiMatchQueryBuilder.tieBreaker(20);
    multiMatchQueryBuilder.type(MultiMatchQueryBuilder.Type.BEST_FIELDS);
    multiMatchQueryBuilder.boost(20);



   SearchResponse searchResponse =  client.prepareSearch()
            .setIndices("blogs")
            .setTypes("blog")
            .setQuery(multiMatchQueryBuilder)
            .execute()
            .actionGet();

}
 
Example #11
Source File: EsTemplateTest.java    From code with Apache License 2.0 5 votes vote down vote up
@Test
public void testHighlightQuery() {
    QueryVO query = new QueryVO();
    query.setKeyword("手机");
    query.setPage(1);
    query.setSize(10);

    // 复合查询
    BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

    // 以下为查询条件, 使用 must query 进行查询组合
    MultiMatchQueryBuilder matchQuery = QueryBuilders.multiMatchQuery(query.getKeyword(), "title", "category");
    boolQuery.must(matchQuery);

    PageRequest pageRequest = PageRequest.of(query.getPage() - 1, query.getSize());

    NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
            .withQuery(boolQuery)
            .withHighlightFields(
                    new HighlightBuilder.Field("title").preTags("<span style=\"color:#F56C6C\">").postTags("</span>"),
                    new HighlightBuilder.Field("category").preTags("<span style=\"color:#F56C6C\">").postTags("</span>"))
            .withPageable(pageRequest)
            .build();
    Page<Item> items = esTemplate.queryForPage(searchQuery, Item.class, highlightResultMapper);

    items.forEach(System.out::println);
    // Item{id=1, title='小米<span style="color:#F56C6C">手机</span>10', category='<span style="color:#F56C6C">手机</span>',
    // brand='小米', price=3499.0, images='http://image.baidu.com/13123.jpg'}
}
 
Example #12
Source File: OptionParser.java    From Elasticsearch with Apache License 2.0 5 votes vote down vote up
public static ParsedOptions parse(MultiMatchQueryBuilder.Type matchType,
                                  @Nullable Map options) throws IllegalArgumentException {
    if (options == null) {
        options = Collections.emptyMap();
    } else {
        // need a copy. Otherwise manipulations on a shared option will lead to strange race conditions.
        options = new HashMap(options);
    }
    ParsedOptions parsedOptions = new ParsedOptions(
            floatValue(options, OPTIONS.BOOST, null),
            analyzer(options.remove(OPTIONS.ANALYZER)),
            zeroTermsQuery(options.remove(OPTIONS.ZERO_TERMS_QUERY)),
            intValue(options, OPTIONS.MAX_EXPANSIONS, FuzzyQuery.defaultMaxExpansions),
            fuzziness(options.remove(OPTIONS.FUZZINESS)),
            intValue(options, OPTIONS.PREFIX_LENGTH, FuzzyQuery.defaultPrefixLength),
            transpositions(options.remove(OPTIONS.FUZZY_TRANSPOSITIONS))
    );

    switch (matchType.matchQueryType()) {
        case BOOLEAN:
            parsedOptions.commonTermsCutoff(floatValue(options, OPTIONS.CUTOFF_FREQUENCY, null));
            parsedOptions.operator(operator(options.remove(OPTIONS.OPERATOR)));
            parsedOptions.minimumShouldMatch(minimumShouldMatch(options.remove(OPTIONS.MINIMUM_SHOULD_MATCH)));
            break;
        case PHRASE:
            parsedOptions.phraseSlop(intValue(options, OPTIONS.SLOP, 0));
            parsedOptions.tieBreaker(floatValue(options, OPTIONS.TIE_BREAKER, null));
            break;
        case PHRASE_PREFIX:
            parsedOptions.phraseSlop(intValue(options, OPTIONS.SLOP, 0));
            parsedOptions.tieBreaker(floatValue(options, OPTIONS.TIE_BREAKER, null));
            parsedOptions.rewrite(rewrite(options.remove(OPTIONS.REWRITE)));
            break;
    }
    if (!options.isEmpty()) {
        raiseIllegalOptions(matchType, options);
    }
    return parsedOptions;
}
 
Example #13
Source File: ElasticQueryBuilder.java    From vind with Apache License 2.0 5 votes vote down vote up
public static SearchSourceBuilder buildExperimentalSuggestionQuery(
            ExecutableSuggestionSearch search,
            DocumentFactory factory) {

        final String searchContext = search.getSearchContext();
        final SearchSourceBuilder searchSource = new SearchSourceBuilder();

        final BoolQueryBuilder baseQuery = QueryBuilders.boolQuery();

        final String[] suggestionFieldNames = Stream.of(getSuggestionFieldNames(search, factory, searchContext))
                .map(name -> name.concat("_experimental"))
                .toArray(String[]::new);

        final MultiMatchQueryBuilder suggestionQuery = QueryBuilders
                .multiMatchQuery(search.getInput(),suggestionFieldNames)
                .type(MultiMatchQueryBuilder.Type.BEST_FIELDS)
                .operator(Operator.OR);

        baseQuery.must(suggestionQuery);

//        if(search.getTimeZone() != null) {
//            query.set(CommonParams.TZ,search.getTimeZone());
//        }

        baseQuery.filter(buildFilterQuery(search.getFilter(), factory, searchContext));

        searchSource.query(baseQuery);

        final HighlightBuilder highlighter = new HighlightBuilder().numOfFragments(0);
        Stream.of(suggestionFieldNames)
                .forEach(highlighter::field);

        searchSource.highlighter(highlighter);
        searchSource.trackScores(SearchConfiguration.get(SearchConfiguration.SEARCH_RESULT_SHOW_SCORE, true));
        searchSource.fetchSource(true);

        //TODO if nested document search is implemented

        return searchSource;
    }
 
Example #14
Source File: YaCyQuery.java    From yacy_grid_mcp with GNU Lesser General Public License v2.1 5 votes vote down vote up
public static QueryBuilder simpleQueryBuilder(String q, boolean or, Boosts boosts) {
    if (q.equals("yacyall")) return new MatchAllQueryBuilder();
    final MultiMatchQueryBuilder qb = QueryBuilders
            .multiMatchQuery(q)
            .operator(or ? Operator.OR : Operator.AND)
            .zeroTermsQuery(ZeroTermsQuery.ALL);
    boosts.forEach((mapping, boost) -> qb.field(mapping.getMapping().name(), boost));
    return qb;
}
 
Example #15
Source File: IndexSearchDaoImpl.java    From herd with Apache License 2.0 4 votes vote down vote up
/**
 * Private method to build a multi match query.
 *
 * @param searchTerm the term on which to search
 * @param queryType the query type for this multi match query
 * @param queryBoost the query boost for this multi match query
 * @param fieldType the field type for this multi match query
 * @param match the set of match fields that are to be searched upon in the index search
 *
 * @return the multi match query
 */
private MultiMatchQueryBuilder buildMultiMatchQuery(final String searchTerm, final MultiMatchQueryBuilder.Type queryType, final float queryBoost,
    final String fieldType, Set<String> match)
{
    // Get the slop value for this multi match query
    Integer phraseQuerySlop = configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_PHRASE_QUERY_SLOP, Integer.class);

    MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(searchTerm).type(queryType);
    multiMatchQueryBuilder.boost(queryBoost);

    if (fieldType.equals(FIELD_TYPE_STEMMED))
    {
        // Get the configured value for 'stemmed' fields and their respective boosts if any
        String stemmedFieldsValue = configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_SEARCHABLE_FIELDS_STEMMED);

        // build the query
        buildMultiMatchQueryWithBoosts(multiMatchQueryBuilder, stemmedFieldsValue, match);

        if (queryType.equals(PHRASE))
        {
            // Set a "slop" value to allow the matched phrase to be slightly different from an exact phrase match
            // The slop parameter tells the match phrase query how far apart terms are allowed to be while still considering the document a match
            multiMatchQueryBuilder.slop(phraseQuerySlop);
        }
    }

    if (fieldType.equals(FIELD_TYPE_NGRAMS))
    {
        // Get the configured value for 'ngrams' fields and their respective boosts if any
        String ngramsFieldsValue = configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_SEARCHABLE_FIELDS_NGRAMS);

        // build the query
        buildMultiMatchQueryWithBoosts(multiMatchQueryBuilder, ngramsFieldsValue, match);
    }

    if (fieldType.equals(FIELD_TYPE_SHINGLES))
    {
        // Set a "slop" value to allow the matched phrase to be slightly different from an exact phrase match
        // The slop parameter tells the match phrase query how far apart terms are allowed to be while still considering the document a match
        multiMatchQueryBuilder.slop(phraseQuerySlop);

        // Get the configured value for 'shingles' fields and their respective boosts if any
        String shinglesFieldsValue = configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_SEARCHABLE_FIELDS_SHINGLES);

        // build the query
        buildMultiMatchQueryWithBoosts(multiMatchQueryBuilder, shinglesFieldsValue, match);
    }

    return multiMatchQueryBuilder;
}
 
Example #16
Source File: SimpleSearchQueryBuilder.java    From onetwo with Apache License 2.0 4 votes vote down vote up
public MultiMatchQueryBuilder multiMatchBuilder(String text, String...fields){
	MultiMatchQueryBuilder q = multiMatchQuery(text, fields);
	queryBuilder = q;
	return q;
}
 
Example #17
Source File: Maker.java    From elasticsearch-sql with Apache License 2.0 4 votes vote down vote up
private ToXContent make(Condition cond, String name, SQLMethodInvokeExpr value) throws SqlParseException {
	ToXContent bqb = null;
	Paramer paramer = null;
	switch (value.getMethodName().toLowerCase()) {
	case "query":
		paramer = Paramer.parseParamer(value);
		QueryStringQueryBuilder queryString = QueryBuilders.queryStringQuery(paramer.value);
		bqb = Paramer.fullParamer(queryString, paramer);
		bqb = fixNot(cond, bqb);
		break;
	case "matchquery":
	case "match_query":
		paramer = Paramer.parseParamer(value);
		MatchQueryBuilder matchQuery = QueryBuilders.matchQuery(name, paramer.value);
		bqb = Paramer.fullParamer(matchQuery, paramer);
		bqb = fixNot(cond, bqb);
		break;
	case "score":
	case "scorequery":
	case "score_query":
		float boost = Float.parseFloat(value.getParameters().get(1).toString());
		Condition subCond = new Condition(cond.getConn(), cond.getName(),null, cond.getOpear(), value.getParameters().get(0),null);
           bqb = QueryBuilders.constantScoreQuery((QueryBuilder) make(subCond)).boost(boost);
		break;
	case "wildcardquery":
	case "wildcard_query":
		paramer = Paramer.parseParamer(value);
		WildcardQueryBuilder wildcardQuery = QueryBuilders.wildcardQuery(name, paramer.value);
		bqb = Paramer.fullParamer(wildcardQuery, paramer);
		break;

	case "matchphrasequery":
	case "match_phrase":
	case "matchphrase":
		paramer = Paramer.parseParamer(value);
		MatchPhraseQueryBuilder matchPhraseQuery = QueryBuilders.matchPhraseQuery(name, paramer.value);
		bqb = Paramer.fullParamer(matchPhraseQuery, paramer);
		break;

       case "multimatchquery":
       case "multi_match":
       case "multimatch":
           paramer = Paramer.parseParamer(value);
           MultiMatchQueryBuilder multiMatchQuery = QueryBuilders.multiMatchQuery(paramer.value);
           bqb = Paramer.fullParamer(multiMatchQuery, paramer);
           break;

       case "spannearquery":
       case "span_near":
       case "spannear":
           paramer = Paramer.parseParamer(value);

           // parse clauses
           List<SpanQueryBuilder> clauses = new ArrayList<>();
           try (XContentParser parser = JsonXContent.jsonXContent.createParser(new NamedXContentRegistry(new SearchModule(Settings.EMPTY, true, Collections.emptyList()).getNamedXContents()), LoggingDeprecationHandler.INSTANCE, paramer.clauses)) {
               while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
                   QueryBuilder query = SpanNearQueryBuilder.parseInnerQueryBuilder(parser);
                   if (!(query instanceof SpanQueryBuilder)) {
                       throw new ParsingException(parser.getTokenLocation(), "spanNear [clauses] must be of type span query");
                   }
                   clauses.add((SpanQueryBuilder) query);
               }
           } catch (IOException e) {
               throw new SqlParseException("could not parse clauses: " + e.getMessage());
           }

           //
           SpanNearQueryBuilder spanNearQuery = QueryBuilders.spanNearQuery(clauses.get(0), Optional.ofNullable(paramer.slop).orElse(SpanNearQueryBuilder.DEFAULT_SLOP));
           for (int i = 1; i < clauses.size(); ++i) {
               spanNearQuery.addClause(clauses.get(i));
           }

           bqb = Paramer.fullParamer(spanNearQuery, paramer);
           break;

       case "matchphraseprefix":
       case "matchphraseprefixquery":
       case "match_phrase_prefix":
           paramer = Paramer.parseParamer(value);
           MatchPhrasePrefixQueryBuilder phrasePrefixQuery = QueryBuilders.matchPhrasePrefixQuery(name, paramer.value);
           bqb = Paramer.fullParamer(phrasePrefixQuery, paramer);
           break;

	default:
		throw new SqlParseException("it did not support this query method " + value.getMethodName());

	}

	return bqb;
}
 
Example #18
Source File: ApiCourseBiz.java    From roncoo-education with MIT License 4 votes vote down vote up
/**
 * 课程搜索列表接口
 *
 * @param courseInfoSearchBO
 * @author wuyun
 */
public Result<Page<CourseInfoSearchPageDTO>> searchList(CourseInfoSearchBO bo) {
	if (StringUtils.isEmpty(bo.getOrgNo())) {
		return Result.error("orgNo不能为空");
	}
	if (bo.getPageCurrent() <= 0) {
		bo.setPageCurrent(1);
	}
	if (bo.getPageSize() <= 0) {
		bo.setPageSize(20);
	}

	if (StringUtils.isEmpty(bo.getCourseName())) {
		return Result.success(new Page<CourseInfoSearchPageDTO>());
	}

	String heightField = "courseName";

	Field hfield = null;
	if (bo.getIsHfield() != null && bo.getIsHfield().equals(IsHfield.YES.getCode())) {
		hfield = new HighlightBuilder.Field(heightField).preTags("<mark>").postTags("</mark>");
	}

	NativeSearchQueryBuilder nsb = new NativeSearchQueryBuilder();
	if (bo.getIsHfield() != null && bo.getIsHfield().equals(IsHfield.YES.getCode())) {
		nsb.withHighlightFields(hfield);// 高亮字段
	}
	nsb.withSort(SortBuilders.scoreSort().order(SortOrder.DESC));// 评分排序(_source)
	nsb.withSort(new FieldSortBuilder("courseSort").order(SortOrder.DESC));// 课程排序(courseSort)
	nsb.withPageable(PageRequest.of(bo.getPageCurrent() - 1, bo.getPageSize()));
	// 复合查询,外套boolQuery
	BoolQueryBuilder qb = QueryBuilders.boolQuery();
	// 精确查询termQuery不分词,must参数等价于AND
	qb.must(QueryBuilders.termQuery("orgNo", bo.getOrgNo()));
	// 模糊查询multiMatchQuery,最佳字段best_fields
	qb.must(QueryBuilders.multiMatchQuery(bo.getCourseName(), "courseName", "lecturerName").type(MultiMatchQueryBuilder.Type.BEST_FIELDS));

	nsb.withQuery(qb);

	org.springframework.data.domain.Page<EsCourse> page = elasticsearchTemplate.queryForPage(nsb.build(), EsCourse.class, resultMapperExt);
	return Result.success(EsPageUtil.transform(page, CourseInfoSearchPageDTO.class));
}