ElasticSearch多个字段分词查询高亮显示

本文介绍如何使用ElasticSearch进行关键字查询,包括分词查询、多字段查询,并实现查询结果的字段高亮显示。通过设置查询参数和高亮显示配置,能够精确匹配并突出显示关键字。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ElasticSearch关键字查询,将关键字分词后查询,多个字段,查询出来字段高亮显示。
查询方法如下:

public List<NewsInfo> searcher2(String key, String indexId, String type) {
        List<NewsInfo> newsInfos= new ArrayList<NewsInfo>();
        try {
            // 创建查询索引,参数productindex表示要查询的索引库为productindex
            SearchRequestBuilder searchRequestBuilder = client
                    .prepareSearch(indexId);

            // 设置查询索引类型,setTypes("productType1", "productType2","productType3");
            // 用来设定在多个类型中搜索
            searchRequestBuilder.setTypes(type);
            // 设置查询类型 1.SearchType.DFS_QUERY_THEN_FETCH = 精确查询 2.SearchType.SCAN
            // = 扫描查询,无序
            searchRequestBuilder.setSearchType(SearchType.DFS_QUERY_THEN_FETCH);
            // 设置查询关键词
//          searchRequestBuilder
//                  .setQuery(QueryBuilders.boolQuery().should(QueryBuilders.termQuery("title", key))
//                          .should(QueryBuilders.termQuery("content", key)));
            QueryStringQueryBuilder queryBuilder = new QueryStringQueryBuilder(key);
            queryBuilder.analyzer("ik_smart");
            queryBuilder.field("title").field("content");
            searchRequestBuilder.setQuery(queryBuilder);
            // 分页应用
             searchRequestBuilder.setFrom(1).setSize(3000);

            // 设置是否按查询匹配度排序
            searchRequestBuilder.setExplain(true);
            // 按照字段排序
            searchRequestBuilder.addSort("publish_time", SortOrder.DESC);
            // 设置高亮显示
            searchRequestBuilder.addHighlightedField("title");
            searchRequestBuilder.addHighlightedField("content");
            searchRequestBuilder
                    .setHighlighterPreTags("<span style=\"color:red\">");
            searchRequestBuilder.setHighlighterPostTags("</span>");
//          searchRequestBuilder.setHighlighterPreTags("<em>");
//          searchRequestBuilder.setHighlighterPostTags("<em>");
            // 执行搜索,返回搜索响应信息
            SearchResponse response = searchRequestBuilder.execute()
                    .actionGet();

            // 获取搜索的文档结果
            SearchHits searchHits = response.getHits();
            SearchHit[] hits = searchHits.getHits();
            // ObjectMapper mapper = new ObjectMapper();
            for (int i = 0; i < hits.length; i++) {
                SearchHit hit = hits[i];
                // 将文档中的每一个对象转换json串值
                String json = hit.getSourceAsString();
                // 将json串值转换成对应的实体对象
                NewsInfo newsInfo = JsonUtils
                        .readToObject(json, NewsInfo.class);
                // 获取对应的高亮域
                Map<String, HighlightField> result = hit.highlightFields();
                // 从设定的高亮域中取得指定域
                HighlightField titleField = result.get("title");
                if (titleField !=null) {
                    // 取得定义的高亮标签
                    Text[] titleTexts = titleField.fragments();
                    // 为title串值增加自定义的高亮标签
                    String title = "";
                    for (Text text : titleTexts) {
                        title += text;
                    }
                    newsInfo.setTitle(title);
                }
                // 从设定的高亮域中取得指定域
                HighlightField contentField = result.get("content");
                if (contentField !=null) {
                    // 取得定义的高亮标签
                    Text[] contentTexts = contentField.fragments();
                    // 为title串值增加自定义的高亮标签
                    String content = "";
                    for (Text text : contentTexts) {
                        content += text;
                    }
                    // 将追加了高亮标签的串值重新填充到对应的对象
                    newsInfo.setContent(content);
                }
                newsInfos.add(newsInfo);
//              System.out.println(newsInfo.toString());
                // 打印高亮标签追加完成后的实体对象
            }
            // 防止出现:远程主机强迫关闭了一个现有的连接
//          Thread.sleep(10000);
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        return newsInfos;
    }

多字段查询方法:

QueryStringQueryBuilder queryBuilder = new QueryStringQueryBuilder(key);
            queryBuilder.analyzer("ik_smart");
            queryBuilder.field("title").field("content");
            searchRequestBuilder.setQuery(queryBuilder);

转载于:https://www.cnblogs.com/luweiwei/p/5968513.html

<think>好的,我现在需要解决用户关于Elasticsearch(ES)使用分词高亮查询导致无法全匹配搜索内容的问题。首先,我得回忆一下ES的基本工作原理,尤其是分词和高亮的部分。用户提到用了分词后,高亮显示的结果不全,可能无法精确匹配搜索内容。这可能是因为分词的步骤将查询词拆分成多个词项,导致高亮时只能匹配到部分词汇。 首先,我应该考虑ES的分词过程。当用户进行搜索时,ES默认会对查询文本进行分词处理,比如使用标准分词器(standard analyzer),它会根据空格和标点拆分文本。例如,搜索“quick brown”会被拆分成“quick”和“brown”两个词项,然后在索引中查找包含这两个词的文档。高亮功能会根据这些分词后的词项来标记匹配的部分,但如果用户希望整个短语完全匹配,这种分词方式可能不准确。 接下来,用户的问题可能出在分词器过于宽松,导致无法精确匹配整个短语。这时候可能需要使用不同的查询类型,比如match_phrase查询,它要求词项按照顺序完全匹配,并且可以通过slop参数允许一定的位置偏移。同时,高亮显示需要正确配置,确保能够反映短语匹配的情况。 另外,用户可能没有意识到索引和搜索时使用的分词器不一致,这也会导致分词结果不匹配。例如,索引时使用了某个自定义分词器,而搜索时使用了不同的设置,使得分词后的词项不一致,从而影响高亮结果。 还有,高亮器的选择也很重要。ES默认使用unified高亮器,但也支持其他类型,比如plain高亮器,可能在处理某些情况时表现不同。此外,高亮设置中的参数,如number_of_fragments、pre_tags和post_tags,也会影响最终显示的效果,需要检查是否配置正确。 可能的解决方案包括: 1. 使用match_phrase查询代替普通的match查询,确保短语完全匹配。 2. 调整分词器,可能在查询时使用不分析的关键字类型(keyword),避免分词。 3. 自定义同义词或使用多字段映射,在索引时保留原始字段的精确值。 4. 检查高亮配置,确保使用正确的字段和分析器。 不过,用户可能在实际操作中遇到具体问题,比如某个特定的查询没有正确高亮,或者分词的规则不符合业务需求。需要根据具体情况调整查询方式或索引设置。例如,对于需要精确匹配的字段,可以设置为keyword类型,这样搜索时必须全匹配,高亮也会正确显示整个词。 还需要考虑是否涉及到中文字符的问题,因为中文分词通常更复杂,使用IK分词器等工具时,如果分词粒度不合适,可能导致无法全匹配。这时候可能需要调整分词器的词典或使用细粒度分词。 总结下来,解决这个问题的步骤应该是:确认查询类型是否正确,检查分词器是否一致,调整高亮配置,可能需要对字段的映射进行调整,或者在查询时使用更精确的匹配方式。同时,可能需要测试不同的配置,查看高亮结果的变化,找到最适合用户需求的方式。</think>针对Elasticsearch使用分词高亮查询后无法全匹配搜索内容的问题,以下是逐步分析与解决方案: --- ### **一、问题根源** 1. **分词机制影响匹配** Elasticsearch默认对文本字段进行分词(如`standard analyzer`),将搜索词拆分为多个词项。例如: - 搜索词`"数据库查询"` → 分词为`["数", "据", "库", "查", "询"]` - 高亮时仅匹配部分词项(如`"数"`和`"库"`),而非完整短语。 2. **查询类型选择不当** 若使用`match`查询,会默认分词后检索,导致无法强制全匹配。 --- ### **二、解决方案** #### **方法1:改用短语匹配(Phrase Match)** **适用场景**:需完全匹配搜索词的顺序和邻近性。 **操作步骤**: 1. 使用`match_phrase`查询: ```json GET /your_index/_search { "query": { "match_phrase": { "content": "数据库查询" } }, "highlight": { "fields": { "content": {} } } } ``` 2. **参数调整**: - `slop`:允许词项间的位置偏移量(默认0,即严格顺序匹配)。 --- #### **方法2:自定义字段映射(Keyword类型)** **适用场景**:需完全精确匹配,禁用分词。 **操作步骤**: 1. 修改字段映射,添加`keyword`类型子字段: ```json PUT /your_index { "mappings": { "properties": { "content": { "type": "text", "fields": { "keyword": { "type": "keyword" } } } } } } ``` 2. 使用`term`查询并指定`keyword`字段: ```json GET /your_index/_search { "query": { "term": { "content.keyword": "数据库查询" } }, "highlight": { "fields": { "content.keyword": {} } } } ``` --- #### **方法3:自定义分词器(Ngram或Edge Ngram)** **适用场景**:需部分匹配但保留高亮完整性。 **操作步骤**: 1. 定义自定义分词器(以`edge_ngram`为例): ```json PUT /your_index { "settings": { "analysis": { "analyzer": { "custom_ngram": { "tokenizer": "custom_tokenizer" } }, "tokenizer": { "custom_tokenizer": { "type": "edge_ngram", "min_gram": 1, "max_gram": 10 } } } } } ``` 2. 搜索时启用`analyzer`参数: ```json GET /your_index/_search { "query": { "match": { "content": { "query": "数据库查询", "analyzer": "custom_ngram" } } }, "highlight": { ... } } ``` --- #### **方法4:调整高亮配置** 优化高亮结果,确保完整匹配部分被标记: ```json "highlight": { "pre_tags": ["<strong>"], "post_tags": ["</strong>"], "fields": { "content": { "type": "plain", // 使用plain高亮器避免二次分词 "number_of_fragments": 0 // 返回完整字段内容 } } } ``` --- ### **三、验证与调试** 1. **分析分词结果**: 使用`_analyze` API检查字段分词效果: ```json GET /your_index/_analyze { "field": "content", "text": "数据库查询" } ``` 2. **检查查询计划**: 添加`explain: true`查看匹配细节: ```json GET /your_index/_search { "explain": true, "query": { ... } } ``` --- ### **四、总结** | 方案 | 优点 | 缺点 | |---------------------|--------------------------|--------------------------| | `match_phrase`查询 | 保留词序和邻近性 | 无法容忍中间插入其他词 | | `keyword`字段 | 精确匹配 | 失去分词搜索灵活性 | | 自定义分词器 | 灵活控制匹配粒度 | 增加索引复杂度 | 根据实际需求选择合适的方案,通常建议结合`match_phrase`和`keyword`多字段映射,兼顾精确匹配与分词搜索。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值