博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,
15年
工作经验,精通Java编程
,高并发设计
,Springboot和微服务
,熟悉Linux
,ESXI虚拟化
以及云原生Docker和K8s
,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。
技术合作请加本人wx(注明来自csdn):foreast_sea
在当今数字化信息爆炸的时代,文本数据的处理和分析变得至关重要。无论是搜索引擎、信息检索系统,还是智能客服、文本挖掘等应用场景,都离不开对文本的准确理解和分析。而在这一过程中,分词作为文本处理的基础环节,其效果直接影响到后续的数据分析和应用效果。
Elasticsearch 作为一款强大的分布式搜索引擎,提供了丰富的文本分析功能。然而,在实际的业务场景中,默认的分词器往往无法满足特定语言、业务需求或复杂文本处理要求。例如,在处理一些专业领域的文本时,如医学、法律等,需要根据专业术语和行业规范进行分词;对于一些具有特殊格式或结构的文本,也需要定制化的分词策略。
这就引出了我们今天要探讨的主题——Java Elasticsearch
自定义分词器。通过自定义分词器,开发者可以根据具体的场景,灵活配置字符过滤器、分词器、词项过滤器等组件,构建一套完全适合自身需求的文本分析流程。掌握这一技术,不仅能够提升文本处理的准确性和效率,还能为各种基于文本的应用带来更强大的功能和更好的用户体验。接下来,让我们一同深入学习如何在 Java 环境中利用 Elasticsearch 实现自定义分词器。
Elasticsearch 的文本分析是一个复杂但有序的过程,主要包括三个核心阶段:字符过滤(Character Filter)、分词(Tokenizer)和词项过滤(Token Filter)。
字符过滤阶段负责在文本被分词之前对原始文本进行预处理。它可以处理诸如 HTML 标签移除、特殊字符转换等任务。例如,如果我们的文本中包含 HTML 标签,字符过滤器可以将这些标签移除,只保留文本内容,这样可以避免在后续分词过程中标签对分词结果的干扰。
分词阶段是将文本按照一定的规则分割成一个个独立的词项(Token)。不同的分词器有不同的分词策略,比如标准分词器会按照单词边界进行分词,而中文分词器会根据中文的语义和语法规则进行分词。分词的准确性直接影响到后续的搜索和分析结果。
词项过滤阶段则是对已经分好的词项进行进一步的处理。比如,将词项转换为小写、移除停用词(如“的”“了”“是”等在文本中没有实际意义的词)、进行词干提取(将单词的不同形式转换为基本形式)等。通过词项过滤,可以进一步优化词项,提高搜索的精准度和召回率。
Elasticsearch 提供了多种内置分词器,以满足不同的基本需求。
虽然这些内置分词器在很多情况下能够满足基本需求,但在面对复杂的业务场景时,往往需要自定义分词器来实现更精准的文本分析。
字符过滤器是文本分析流程的第一步,它用于对原始文本进行预处理。Elasticsearch 提供了一些内置的字符过滤器,同时也允许开发者自定义。
Hello, world!
”,经过 HTML Strip Character Filter 处理后,会得到“Hello, world!”。在实际应用中,如果我们的文本数据来源包含 HTML 格式的内容,使用这个字符过滤器可以有效地清理文本,避免 HTML 标签对后续分词和分析的影响。自定义字符过滤器需要继承 AbstractCharFilterFactory
类,并实现相应的方法。在 Java 中,我们可以这样实现一个简单的自定义字符过滤器:
import org.apache.lucene.analysis.CharFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.util.CharFilterFactory;
import org.elasticsearch.common.settings.Settings;
import java.io.IOException;
import java.io.Reader;
public class CustomCharFilterFactory extends CharFilterFactory {
public CustomCharFilterFactory(Settings settings) {
super(settings);
}
@Override
public CharFilter create(Reader input) throws IOException {
// 这里可以实现自定义的字符过滤逻辑,例如对特定字符的替换
return new CustomCharFilter(input);
}
private static class CustomCharFilter extends CharFilter {
public CustomCharFilter(Reader in) {
super(in);
}
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
// 实现具体的字符读取和过滤逻辑
return super.read(cbuf, off, len);
}
}
}
分词器是自定义分词器的核心组件,它负责将文本分割成一个个词项。Elasticsearch 提供了多种内置分词器,同时也支持开发者自定义。
自定义分词器需要继承 TokenizerFactory
类,并实现相应的方法。以下是一个简单的自定义分词器示例:
import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.util.TokenizerFactory;
import org.elasticsearch.common.settings.Settings;
import java.io.Reader;
public class CustomTokenizerFactory extends TokenizerFactory {
public CustomTokenizerFactory(Settings settings) {
super(settings);
}
@Override
public Tokenizer create(Reader input) {
// 这里可以实现自定义的分词逻辑
return new CustomTokenizer(input);
}
private static class CustomTokenizer extends Tokenizer {
public CustomTokenizer(Reader input) {
super(input);
}
@Override
public boolean incrementToken() throws IOException {
// 实现具体的分词逻辑,填充词项
return false;
}
}
}
词项过滤器用于对已经分好的词项进行进一步的处理和转换。
自定义词项过滤器需要继承 TokenFilterFactory
类,并实现相应的方法。下面是一个简单的自定义词项过滤器示例:
import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.util.TokenFilterFactory;
import org.elasticsearch.common.settings.Settings;
import java.io.IOException;
public class CustomTokenFilterFactory extends TokenFilterFactory {
public CustomTokenFilterFactory(Settings settings) {
super(settings);
}
@Override
public TokenFilter create(TokenStream input) throws IOException {
// 这里可以实现自定义的词项过滤逻辑
return new CustomTokenFilter(input);
}
private static class CustomTokenFilter extends TokenFilter {
public CustomTokenFilter(TokenStream input) {
super(input);
}
@Override
public boolean incrementToken() throws IOException {
// 实现具体的词项过滤逻辑
return super.incrementToken();
}
}
}
在 Elasticsearch 中,配置自定义分词器需要在 elasticsearch.yml
文件或索引的映射文件中进行。以下是在索引映射文件中配置自定义分词器的示例:
{
"settings": {
"analysis": {
"char_filter": {
"custom_char_filter": {
"type": "mapping",
"mappings": [
"&=>and"
]
}
},
"tokenizer": {
"custom_tokenizer": {
"type": "pattern",
"pattern": "\\W+"
}
},
"filter": {
"custom_token_filter": {
"type": "lowercase"
}
},
"analyzer": {
"custom_analyzer": {
"type": "custom",
"char_filter": [
"custom_char_filter"
],
"tokenizer": "custom_tokenizer",
"filter": [
"custom_token_filter"
]
}
}
}
}
}
在上述配置中,我们定义了一个自定义字符过滤器 custom_char_filter
,它将“&”替换为“and”;一个自定义分词器 custom_tokenizer
,它根据非单词字符进行分词;一个自定义词项过滤器 custom_token_filter
,它将词项转换为小写。最后,我们定义了一个自定义分析器 custom_analyzer
,它组合了上述定义的字符过滤器、分词器和词项过滤器。
在 Java 中使用自定义分词器,我们需要借助 Elasticsearch 的 Java API。首先,我们需要添加相应的 Maven 依赖:
<dependency>
<groupId>org.elasticsearch.clientgroupId>
<artifactId>elasticsearch-rest-high-level-clientartifactId>
<version>7.17.0version>
dependency>
<dependency>
<groupId>org.elasticsearchgroupId>
<artifactId>elasticsearchartifactId>
<version>7.17.0version>
dependency>
上述依赖中,elasticsearch-rest-high-level-client
提供了与 Elasticsearch 进行交互的高级 REST 客户端 API,elasticsearch
则是 Elasticsearch 的核心库。
接下来,我们可以在 Java 代码中使用自定义分词器进行文本分析:
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.analysis.AnalyzerProvider;
import org.elasticsearch.index.analysis.IndexAnalyzers;
import org.elasticsearch.rest.RestClient;
import java.io.IOException;
import java.util.Map;
public class CustomAnalyzerExample {
public static void main(String[] args) throws IOException {
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("localhost", 9200, "http")));
GetIndexRequest request = new GetIndexRequest("your_index_name");
GetIndexResponse response = client.indices().get(request);
Settings settings = response.getSettings();
IndexAnalyzers indexAnalyzers = IndexAnalyzers.fromSettings(settings);
AnalyzerProvider analyzerProvider = indexAnalyzers.getCustom("custom_analyzer");
Analyzer analyzer = analyzerProvider.get();
TokenStream tokenStream = analyzer.tokenStream("text", "Hello, &world! How are you?");
CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
tokenStream.reset();
while (tokenStream.incrementToken()) {
System.out.println(charTermAttribute.toString());
}
tokenStream.end();
tokenStream.close();
client.close();
}
}
在上述代码中,我们首先创建了一个 RestHighLevelClient
实例,用于与 Elasticsearch 进行通信。然后,我们通过 GetIndexRequest
获取索引的设置信息,从中提取出我们定义的自定义分析器 custom_analyzer
。接着,我们使用这个分析器对文本“Hello, &world! How are you?”进行分词,并输出分词结果。
在电商系统中,商品标题的准确分词对于商品搜索和推荐至关重要。例如,当用户搜索“苹果手机”时,我们希望系统能够准确地将商品标题中包含“苹果手机”相关的商品检索出来。然而,默认的分词器可能无法很好地处理一些复杂的商品标题,比如包含品牌名、型号、功能等多种信息的标题。
为了优化电商商品标题的分词效果,我们设计了一个自定义分词器。
在 Java 中实现上述自定义分词器,并将其应用到电商商品标题的索引和搜索中。通过实际的测试数据验证,使用自定义分词器后,商品搜索的准确率和召回率都有了显著提升,用户能够更准确地找到自己需要的商品。
通过本文的学习,我们深入了解了 Java Elasticsearch 自定义分词器的相关知识。从 Elasticsearch 文本分析的基础原理,到自定义分词器的各个组件(字符过滤器、分词器、词项过滤器)的介绍,再到构建自定义分词器的具体步骤和实际案例应用,我们一步步掌握了如何根据特定的语言、业务需求或文本处理要求,打造适合自身场景的文本分析流程。
在实际的项目开发中,根据具体的业务场景灵活运用自定义分词器,可以极大地提升文本处理的准确性和效率,为用户提供更好的搜索和分析体验。希望本文的内容能够对广大开发者在 Elasticsearch 文本分析领域的工作有所帮助。