Elasticsearch 6.2.4中如何通过ID片段检索文档?(Rest High Level Client)
针对文档ID片段检索的最优实现方案(Elasticsearch 6.2.4 + Rest High Level Client)
首先,咱们得明确:Elasticsearch默认的_id字段是keyword类型,不会被分词,所以直接用普通的match查询是搜不到片段的。下面分两种场景给出最优方案:
场景1:快速实现(无需修改现有映射)
如果你的数据量不大,或者不想改动现有索引结构,可以直接用Wildcard查询或者Regexp查询来匹配_id的片段。这种方式上手快,缺点是如果通配符放在开头(比如*ne),性能会稍差(因为无法利用前缀索引)。
Java代码示例(Rest High Level Client)
import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.builder.SearchSourceBuilder; import java.io.IOException; public class IdFragmentSearch { public static void searchByIdFragment(RestHighLevelClient client, String fragment) throws IOException { // 构建搜索请求 SearchRequest searchRequest = new SearchRequest("people"); searchRequest.types("user"); // 6.x版本需要指定类型 // 构建查询:匹配_id中包含指定片段的文档 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); sourceBuilder.query(QueryBuilders.wildcardQuery("_id", "*" + fragment + "*")); // 如果需要更精确的正则匹配,可以用RegexpQuery: // sourceBuilder.query(QueryBuilders.regexpQuery("_id", ".*" + fragment + ".*")); searchRequest.source(sourceBuilder); // 执行搜索并处理结果 SearchResponse response = client.search(searchRequest); // 遍历结果(示例) response.getHits().forEach(hit -> { System.out.println("文档ID: " + hit.getId()); System.out.println("文档内容: " + hit.getSourceAsString()); }); } }
场景2:高性能方案(修改索引映射)
如果数据量较大,或者需要频繁进行这类片段检索,建议新增一个专门的字段(比如doc_id),并配置ngram分词器,让Elasticsearch提前为ID的所有子片段建立倒排索引,这样查询性能会大幅提升。
步骤1:修改索引映射
首先需要更新people索引的映射,添加doc_id字段并配置ngram分词器:
PUT /people/_mapping/user { "properties": { "doc_id": { "type": "text", "analyzer": "ngram_analyzer", "search_analyzer": "standard" } } } PUT /people/_settings { "analysis": { "analyzer": { "ngram_analyzer": { "tokenizer": "ngram_tokenizer" } }, "tokenizer": { "ngram_tokenizer": { "type": "ngram", "min_gram": 2, "max_gram": 5 // 根据你的ID长度调整,比如你的ID是3位,max_gram设为3即可 } } } }
步骤2:同步现有数据
把已有的_id值同步到doc_id字段:
POST /people/_update_by_query { "script": { "source": "ctx._source.doc_id = ctx._id" } }
(如果是新写入的文档,可以在写入时直接把_id赋值给doc_id,或者用Ingest Pipeline自动处理)
步骤3:Java代码实现高效查询
import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.builder.SearchSourceBuilder; import java.io.IOException; public class HighPerformanceIdSearch { public static void searchByDocIdFragment(RestHighLevelClient client, String fragment) throws IOException { SearchRequest searchRequest = new SearchRequest("people"); searchRequest.types("user"); SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); // 直接用match查询doc_id字段,性能远高于wildcard sourceBuilder.query(QueryBuilders.matchQuery("doc_id", fragment)); searchRequest.source(sourceBuilder); SearchResponse response = client.search(searchRequest); response.getHits().forEach(hit -> { System.out.println("文档ID: " + hit.getId()); System.out.println("文档内容: " + hit.getSourceAsString()); }); } }
注意事项
- 如果使用Wildcard查询,尽量避免把通配符放在开头(比如
*ne),这样会导致Elasticsearch无法利用前缀索引,性能下降明显。 - Ngram分词器的
min_gram和max_gram参数需要根据你的ID长度合理设置,比如你的ID都是3位,设置min_gram=2、max_gram=3就足够覆盖所有可能的2-3位片段。 - Elasticsearch 6.x已经开始弱化"类型(type)"的概念,如果你后续升级到7.x及以上,需要移除
types("user")这部分代码。
内容的提问来源于stack exchange,提问作者driveall
相关产品推荐
相关产品推荐

