您的位置:

Elasticsearch高亮功能详解

一、Elasticsearch高亮显示name字段

在Elasticsearch中,高亮功能是通过在搜索结果中对搜索关键字进行标记、突出显示的功能。为了快速了解高亮显示,我们可以通过对name字段进行高亮来体验一下。

curl -X GET "localhost:9200/my_index/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "name": "elasticsearch"
    }
  },
  "highlight": {
    "fields": {
      "name": {
        "number_of_fragments": 3
      }
    }
  }
}
'

通过以上代码,可以看到在搜索结果中,对包含搜索关键字的name字段进行了突出显示。

二、Elasticsearch启动

在使用Elasticsearch高亮功能前,我们需要先启动Elasticsearch。

cd elasticsearch-7.14.1/bin
./elasticsearch

以上代码启动Elasticsearch。如果您已经安装了 Elasticsearch,可以直接在终端输入 elasticsearch 命令启动。如果您是通过安装包或者其他方式安装的Elasticsearch,命令会有所不同,请自行查询。

三、Elasticsearch高亮查询

在Elasticsearch中,高亮查询是用于查找指定字段中包含关键字的文档,并将匹配关键字的部分进行标记、突出显示的功能。

GET /my_index/_search
{
    "query": {
        "match_phrase" : {
            "text" : "elasticsearch"
        }
    },
    "highlight": {
        "fields" : {
            "text" : {}
        }
    }
}

以上代码用于查询text字段中包含关键字“elasticsearch”的文档,并对匹配的部分进行标记、突出显示。

四、Elasticsearch高亮内容回填

Elasticsearch高亮功能支持将高亮显示的内容回填到原有的数据中。回填功能主要会在搜索结果中将高亮显示的内容回填到原始文档中。

GET /my_index/_search
{
    "query": {
        "match_phrase" : {
            "text" : "elasticsearch"
        }
    },
    "highlight": {
        "fields" : {
            "text" : {}
        },
        "pre_tags" : [""],
        "post_tags" : [""]
    }
}

  

以上代码用于将在搜索结果中搜索关键字“elasticsearch”并对匹配部分进行标记、突出显示,同时将标记的信息回填到原始的文档中。

五、Elasticsearch高亮设置

Elasticsearch高亮功能支持对高亮部分进行设置,如设置标记色、截取长度、显示位置等等。常见设置如下:

GET /my_index/_search
{
    "query": {
        "match_phrase" : {
            "text" : "elasticsearch"
        }
    },
    "highlight": {
        "fields" : {
            "text" : {"number_of_fragments" : 2, "fragment_size" : 150}
        },
        "pre_tags" : [""],
        "post_tags" : [""]
    }
}

  

以上代码用于将在搜索结果中搜索关键字“elasticsearch”并对匹配部分进行标记、突出显示,同时设置每个匹配部分最多返回2段节选,每段节选最多返回150个字符。

六、Elasticsearch高亮跳转

在搜索结果中点击高亮显示的部分可以跳转至原始文档中的对应位置。

涉及到html标签的部分,在此省略转义处理,下同。

curl -X GET "localhost:9200/my_index/_search?pretty" -H 'Content-Type: application/json' -d'
{
  ...
  "highlight": {
      "pre_tags": [""],
      "post_tags": [""],
      "fields": {
          "title": {},
          "content": {},
          "comments.comment": {}
      }
  }
}
'

以上代码用于将在搜索结果中搜索关键字并对匹配部分进行标记、突出显示,并设置每个匹配部分的开始和结束标记,以便实现跳转到指定部分的效果。

七、Elasticsearch高亮还原

当文档中含有HTML或其他转义字符时,高亮显示的内容未必适用于所有界面。我们需要用到escape_html参数,以便还原标记后的内容,即将文档中的HTML标记转义还原。

curl -X GET "localhost:9200/my_index/_search?pretty" -H 'Content-Type: application/json' -d'
{
  ...
  "highlight": {
      "fields": {
          "title": {"escape": true}
      }
  }
}
'

以上代码用于将在搜索结果中搜索关键字并对匹配部分进行标记、突出显示,并设置escapte_html参数以便还原HTML标记。

八、Elasticsearch高亮用什么框架实现

Elasticsearch的高亮功能可以通过多种框架实现,如Java、Python等。以下是Java实现的示例代码:

public class SearchDemo {
    private TransportClient client;
    private static final String ES_CLUSTER_NAME = "my_cluster";
    private static final String ES_SERVER_IP = "127.0.0.1:9300;";

    public void initialize() throws Exception {
        //设置连接池配置
        Settings settings = Settings.builder().put("cluster.name", ES_CLUSTER_NAME).build();
        TransportClient transportClient = new PreBuiltTransportClient(settings).addTransportAddresses(
                new TransportAddress(InetAddress.getByName(ES_SERVER_IP.split(":")[0]), Integer
                        .valueOf(ES_SERVER_IP.split(":")[1])));
        this.client = transportClient;
    }

    public void search(String index, String type, String name) {
        QueryBuilder query = QueryBuilders.matchQuery("name", name);
        HighlightBuilder hiBuilder = new HighlightBuilder();
        hiBuilder.preTags("");
        hiBuilder.postTags("");
        hiBuilder.field("name");
        SearchResponse response = client.prepareSearch(index).setTypes(type).setQuery(query)
                .highlighter(hiBuilder).get();
        SearchHits hits = response.getHits();
        for (SearchHit hit : hits) {
            Map fields = hit.getHighlightFields();
            HighlightField text = fields.get("name");
            Text[] fragments = text.fragments();
            String fragmentString = fragments[0].string();
            System.out.println(fragmentString);
        }
    }
}

  

以上代码用于连接Elasticsearch并设置连接池配置,然后执行关键字查询并对匹配部分进行标记、突出显示并输出。可以通过Java语法来实现Elasticsearch高亮功能。

九、Elasticsearch高亮只能高亮一个字

在使用Elasticsearch高亮功能时,当需要高亮的部分只有一个字时,容易出现不亮的情况。这是由于Elasticsearch对高亮的片段长度进行限制,导致出现不亮的情况。可以通过以下方式解决这个问题:

GET /my_index/_search
{
    "query": {
        "match": {
            "text": "elasticsearch"
        }
    },
    "highlight": {
        "fields": {
            "text": {
                "number_of_fragments": 0,
                "require_field_match": false,
                "pre_tags": [""],
                "post_tags": [""]
            }
        }
    }
}

以上代码用于将一行文本中的每个字符都作为单独的标记选项,以进行高亮显示。

十、Elasticsearch高亮截取中文字符串

在使用Elasticsearch高亮功能时,由于中文长度不稳定,会导致一些字符不被高亮显示,而不同于其他关键字匹配的字符。可以使用第三方库中的SubstringScore分析中文字符,并对匹配部分进行截取,以解决该问题。下面是String分析的示例代码:

Analyzer analyzer = new StandardAnalyzer();    // 使用标准分词器
QueryParser parser = new QueryParser("", analyzer);   // 构建QueryParser对象
Query query = parser.parse("text");  // QueryParser.parse(String str)将会调用analyzer对象
TokenStream tokenStream = analyzer.tokenStream("", new StringReader(content));
CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
tokenStream.reset();
float score = 0;
int start = 0;
int end = 0;
while (tokenStream.incrementToken()) {
    String term = charTermAttribute.toString();
    String pattern = term.replace("*", "");
    if (pattern.length() < 2)
        continue;
    int loc = content.indexOf(pattern, start);
    if (loc != -1) {
        if (score == 0) {
            start = loc;
            end = start + pattern.length();
        } else {
            if (start > loc)
                start = loc;
            if (end < loc + pattern.length())
                end = loc + pattern.length();
        }
        score +=1;
    }
}
String fragmentString = "";
if (score != 0) {
    if (start >FragSize / 2)
        start -= Emergent.length() / 2;
    if (end + FragSize / 2 < content.length())
        end += Emergent.length() / 2;
    if (start < 0)
        start = 0;
    if (end >= content.length())
        end = content.length() - 1;
    fragmentString = getHighlightSnippet(content, start, end);
}

以上代码使用StringTokenizer函数处理中文字符,并对关键字进行截取和高亮显示,并解决了中文字符不稳定导致有些字符不被高亮显示的问题。