ES存储document时,会根据数据对应的field类型建立对应的索引。通常来说只创建倒排索引,倒排索引是为了搜索而存在的,但如果对数据进行排序、聚合、过滤等操作时,再使用倒排索引就明显不适合了。这个时候就需要在ES中创建正排索引(doc values)。doc values保存在磁盘中,如果OS Cache系统缓存的空间足够大,ES会缓存doc values,因此性能还是很不错的。
问: 为什么说倒排索引不适合做聚合、排序等操作?
答: 比如有数据如下:
{
“name” : “张三”,
“remark” : “java开发工程师”,
"_id": 1
}
{
“name” : “李四”,
“remark” : “java架构工程师”,
"_id": 2
}
为remark字段创建倒排索引:
Term | Doc |
---|---|
java | 1,2 |
开发 | 1 |
架构 | 2 |
工程师 | 1,2 |
如果在倒排索引的基础上进行聚合,那么到底是根据java进行聚合呢、还是根据开发或者架构来聚合呢?不难发现,用哪一个都不合适。排序也是如此。倒排索引因分词得到了许多好处,但也因此留下了弊端。
所以,为了应对这种不需要分词的需求和场景,ES设计了正排索引Doc values。Doc values不会对字段作任何分词处理,皆保留原值。
正排索引的大致结构如下:
Doc values | Values |
---|---|
Doc1 | java开发工程师 |
Doc2 | java架构工程师 |
ES会根据document中每个字段是否分词,有选择性的实现字段对应的倒排索引或正排索引(Doc values)。
比如,如果字段类型为keyword,long,date,那么这些类型修饰的字段一定会有正排索引(Doc values)。
比如,如果字段类型为text,则只会有倒排索引,不会主动创建正排索引。
如果想在同一个字段中,既实现正排索引,又实现倒排索引,只需要使用fielddata即可,实现方式如下:
若遇到聚合、排序等需求时,ES使用test_field.keyword,若遇到搜索需求时,ES使用test_field。
{
"mappings": {
"type": {
"properties": {
"test_field": {
"type": "text",
"analyzer": "standard",
"fields": {
"keyword": {
"type": "keyword"
}
}
}
}
}
}
}