将 Jieba 分词 安装到 Elasticsearch 并结合 Java 实现是一个复杂但有效的方案。由于 Elasticsearch 并没有原生支持结巴分词,需要通过自定义插件或者应用层预处理的方式来实现。
下面是两种方案来整合 Jieba 分词与 Elasticsearch 并结合 Java 使用的具体步骤。
方案一:自定义 Elasticsearch 分词插件(复杂度较高)
在这个方案中,你需要开发一个自定义的 Elasticsearch 分词插件,将 Jieba 分词集成进 Elasticsearch。这个方法需要对 Elasticsearch 插件开发有一定了解。
1. 创建自定义 Elasticsearch 插件
-
配置 Maven 项目
使用 Maven 创建一个项目,配置
pom.xml
,让它依赖于 Elasticsearch 的插件开发库。<dependencies> <dependency> <groupId>org.elasticsearch.plugin</groupId> <artifactId>elasticsearch-plugin-classloader</artifactId> <version>7.17.7</version> <!-- 对应你的ES版本 --> </dependency> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>7.17.7</version> <!-- 对应你的ES版本 --> </dependency> <dependency> <groupId>com.huaban</groupId> <artifactId>jieba-analysis</artifactId> <version>1.0.2</version><!-- 对应你选择的结巴依赖 --> </dependency> </dependencies>
-
编写分词插件
创建一个继承
TokenizerFactory
的类,利用JiebaAnalyzer
来进行分词。import com.huaban.analysis.jieba.JiebaSegmenter; import org.apache.lucene.analysis.Tokenizer; import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; import org.apache.lucene.util.AttributeFactory; public class JiebaTokenizer extends Tokenizer { private final CharTermAttribute charTermAttr = addAttribute(CharTermAttribute.class); private JiebaSegmenter segmenter = new JiebaSegmenter(); private Iterator<String> iterator; @Override public boolean incrementToken() throws IOException { clearAttributes(); if (iterator == null) { String content = new String(input.readAllChars()); iterator = segmenter.process(content, JiebaSegmenter.SegMode.SEARCH).stream().map(item -> item.word).iterator(); } if (iterator.hasNext()) { charTermAttr.append(iterator.next()); return true; } return false; } }
-
实现分词器工厂类
实现工厂类用于创建 Jieba 分词器:
import org.elasticsearch.index.analysis.AbstractTokenizerFactory; import org.elasticsearch.index.analysis.TokenizerFactory; import org.elasticsearch.index.settings.IndexSettings; public class JiebaTokenizerFactory extends AbstractTokenizerFactory { public JiebaTokenizerFactory(IndexSettings indexSettings) { super(indexSettings); } @Override public Tokenizer create() { return new JiebaTokenizer(); } }
-
配置插件描述文件
在
plugin-descriptor.properties
中配置插件信息:plugin.name=jieba-analysis plugin.description=Jieba Analysis Plugin for Elasticsearch plugin.classname=com.example.JiebaAnalysisPlugin
-
打包插件并安装到 Elasticsearch
使用 Maven 打包插件,并将其安装到 Elasticsearch:
./bin/elasticsearch-plugin install file:///path/to/jieba-analysis-plugin.zip
然后重启 Elasticsearch。
2. 使用 Java 与 Elasticsearch 交互
-
创建 Elasticsearch 客户端
使用 Elasticsearch 提供的 Java 高级客户端进行与 ES 的交互:
import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.common.xcontent.XContentType; public class ElasticSearchClient { private static final RestHighLevelClient client = new RestHighLevelClient( RestClient.builder(new HttpHost("localhost", 9200, "http"))); public static void main(String[] args) throws IOException { IndexRequest request = new IndexRequest("test_index") .source("{ \"content\": \"我喜欢Elasticsearch\" }", XContentType.JSON); client.index(request, RequestOptions.DEFAULT); client.close(); } }
-
创建索引并使用 Jieba 分词器
在创建索引时,指定你自定义的
jieba_tokenizer
分词器:PUT /test_index { "settings": { "analysis": { "tokenizer": { "jieba_tokenizer": { "type": "jieba_tokenizer" } }, "analyzer": { "jieba_analyzer": { "type": "custom", "tokenizer": "jieba_tokenizer" } } } } }
3. 查询测试
使用自定义的 jieba_analyzer
对文档进行查询:
GET /test_index/_search
{
"query": {
"match": {
"content": {
"query": "Elasticsearch",
"analyzer": "jieba_analyzer"
}
}
}
}
方案二:应用层预处理分词(更简单,推荐)
与其直接在 Elasticsearch 中集成 Jieba 分词器,另一种更简单且灵活的方法是在应用层使用结巴分词,然后将处理后的分词结果存入 Elasticsearch。这种方案的实现步骤相对较为简单。
1. 在应用层进行结巴分词
-
使用 Jieba 分词
在 Java 项目中使用结巴分词的 Java 版本
jieba-analysis
:<dependency> <groupId>com.huaban</groupId> <artifactId>jieba-analysis</artifactId> <version>1.0.2</version> </dependency>
-
分词示例
使用 Jieba 分词对输入的中文文本进行处理:
import com.huaban.analysis.jieba.JiebaSegmenter; public class JiebaExample { public static void main(String[] args) { JiebaSegmenter segmenter = new JiebaSegmenter(); String text = "我喜欢学习Elasticsearch"; System.out.println(segmenter.process(text, JiebaSegmenter.SegMode.SEARCH)); } }
输出结果类似于:[[我, 0, 1], [喜欢, 1, 3], [学习, 3, 5], [elasticsearch, 5, 18]]
-
将分词结果存入 Elasticsearch
Jieba 分词后的详细结构信息。这个结果包含了每个分词的起始位置和结束位置,而不仅仅是分词的文本。
JiebaSegmenter 的 process 方法返回的是 List<SegToken>,而 SegToken 是一个对象,里面包括了:
1.word(词语本身),比如 "我"、"喜欢"、"学习"。
2.start offset(词的起始位置),表示词语在原始文本中的开始字符索引。
3.end offset(词的结束位置),表示词语在原始文本中的结束字符索引。
因此,返回的结构类似于 [词语, 起始位置, 结束位置]。如果你只想获取分词结果,而不需要起始位置和结束位置的信息,你可以将 SegToken 转换为词语本身,并将处理后的分词结果作为数组或者字符串存入 Elasticsearch:
import com.huaban.analysis.jieba.JiebaSegmenter; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xcontent.XContentFactory; public class JiebaExample { public static void main(String[] args) { JiebaSegmenter segmenter = new JiebaSegmenter(); String text = "我喜欢学习Elasticsearch"; // 获取分词结果 List<String> tokens = segmenter.process(text, JiebaSegmenter.SegMode.SEARCH).stream().map(item -> item.word).collect(Collectors.toList()); // 构建 JSON 文档 XContentBuilder builder = XContentFactory.jsonBuilder(); builder.startObject(); builder.field("content", text); builder.field("tokens", tokens); // 自动转换为 JSON 数组 builder.endObject(); // 创建 IndexRequest IndexRequest request = new IndexRequest("test_index") .source(builder); // 执行请求 client.index(request, RequestOptions.DEFAULT); }
2. 在 Elasticsearch 中查询
当用户查询时,你可以直接对分词后的字段进行匹配查询:
GET /test_index/_search
{
"query": {
"match": {
"tokens": "Elasticsearch"
}
}
}
总结
- 方案一:自定义 Elasticsearch 分词插件:这种方式更为复杂,但能将 Jieba 分词完全集成到 Elasticsearch 中,提供实时分词处理。需要编写插件、打包、安装等步骤。
- 方案二:应用层分词处理:这种方式更为简单,灵活性高,适合在将数据存入 Elasticsearch 之前先在应用层进行分词处理,不需要对 Elasticsearch 进行定制。
对于大部分应用场景,方案二 更为推荐,因为它简化了开发流程,并且允许你在应用层使用更加灵活的分词策略。如果对自定义插件有深入需求,方案一 则可以作为高级选项。