You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by qi...@apache.org on 2020/04/13 13:06:50 UTC

[incubator-iotdb] branch master updated: Add new Fill function docs and rearrange SystemDesign doc index (#1036)

This is an automated email from the ASF dual-hosted git repository.

qiaojialin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 6a3219b  Add new Fill function docs and rearrange SystemDesign doc index (#1036)
6a3219b is described below

commit 6a3219bcd301d44aed8913fe1af9fa227480d4e4
Author: wshao08 <59...@users.noreply.github.com>
AuthorDate: Mon Apr 13 21:06:35 2020 +0800

    Add new Fill function docs and rearrange SystemDesign doc index (#1036)
    
    * Add new Fill function docs and rearrange SystemDesign doc index
---
 docs/SystemDesign/5-DataQuery/1-DataQuery.md       |  13 +-
 ...dificationHandle.md => 3-ModificationHandle.md} |   0
 .../{3-RawDataQuery.md => 4-RawDataQuery.md}       |   0
 ...4-AggregationQuery.md => 5-AggregationQuery.md} |   0
 .../{5-GroupByQuery.md => 6-GroupByQuery.md}       |   0
 .../5-DataQuery/{6-LastQuery.md => 7-LastQuery.md} |   0
 ...ignByDeviceQuery.md => 8-AlignByDeviceQuery.md} |   0
 docs/SystemDesign/5-DataQuery/9-FillFunction.md    | 149 +++++++++++++++++++++
 docs/zh/SystemDesign/5-DataQuery/1-DataQuery.md    |  13 +-
 ...dificationHandle.md => 3-ModificationHandle.md} |   0
 .../{3-RawDataQuery.md => 4-RawDataQuery.md}       |   0
 ...4-AggregationQuery.md => 5-AggregationQuery.md} |   0
 .../{5-GroupByQuery.md => 6-GroupByQuery.md}       |   0
 .../5-DataQuery/{6-LastQuery.md => 7-LastQuery.md} |   0
 ...ignByDeviceQuery.md => 8-AlignByDeviceQuery.md} |   0
 docs/zh/SystemDesign/5-DataQuery/9-FillFunction.md | 148 ++++++++++++++++++++
 site/src/main/.vuepress/config.js                  |  28 ++--
 17 files changed, 326 insertions(+), 25 deletions(-)

diff --git a/docs/SystemDesign/5-DataQuery/1-DataQuery.md b/docs/SystemDesign/5-DataQuery/1-DataQuery.md
index 9325e45..d9a2f6c 100644
--- a/docs/SystemDesign/5-DataQuery/1-DataQuery.md
+++ b/docs/SystemDesign/5-DataQuery/1-DataQuery.md
@@ -35,9 +35,10 @@ In order to achieve the above kinds of queries, a basic query component for a si
 ## Related documents
 
 * [Basic query components](/SystemDesign/5-DataQuery/2-SeriesReader.html)
-* [Raw data query](/SystemDesign/5-DataQuery/3-RawDataQuery.html)
-* [Aggregate query](/SystemDesign/5-DataQuery/4-AggregationQuery.html)
-* [Downsampling query](/SystemDesign/5-DataQuery/5-GroupByQuery.html)
-* [Recent timestamp query](/SystemDesign/5-DataQuery/6-LastQuery.html)
-* [Align by device query](/SystemDesign/5-DataQuery/7-AlignByDeviceQuery.html)
-* [Modification handle](/SystemDesign/5-DataQuery/8-ModificationHandle.html)
\ No newline at end of file
+* [Modification handle](/SystemDesign/5-DataQuery/3-ModificationHandle.html)
+* [Raw data query](/SystemDesign/5-DataQuery/4-RawDataQuery.html)
+* [Aggregate query](/SystemDesign/5-DataQuery/5-AggregationQuery.html)
+* [Downsampling query](/SystemDesign/5-DataQuery/6-GroupByQuery.html)
+* [Recent timestamp query](/SystemDesign/5-DataQuery/7-LastQuery.html)
+* [Align by device query](/SystemDesign/5-DataQuery/8-AlignByDeviceQuery.html)
+* [Fill function](/SystemDesign/5-DataQuery/9-FillFunction.html)
\ No newline at end of file
diff --git a/docs/SystemDesign/5-DataQuery/8-ModificationHandle.md b/docs/SystemDesign/5-DataQuery/3-ModificationHandle.md
similarity index 100%
rename from docs/SystemDesign/5-DataQuery/8-ModificationHandle.md
rename to docs/SystemDesign/5-DataQuery/3-ModificationHandle.md
diff --git a/docs/SystemDesign/5-DataQuery/3-RawDataQuery.md b/docs/SystemDesign/5-DataQuery/4-RawDataQuery.md
similarity index 100%
rename from docs/SystemDesign/5-DataQuery/3-RawDataQuery.md
rename to docs/SystemDesign/5-DataQuery/4-RawDataQuery.md
diff --git a/docs/SystemDesign/5-DataQuery/4-AggregationQuery.md b/docs/SystemDesign/5-DataQuery/5-AggregationQuery.md
similarity index 100%
rename from docs/SystemDesign/5-DataQuery/4-AggregationQuery.md
rename to docs/SystemDesign/5-DataQuery/5-AggregationQuery.md
diff --git a/docs/SystemDesign/5-DataQuery/5-GroupByQuery.md b/docs/SystemDesign/5-DataQuery/6-GroupByQuery.md
similarity index 100%
rename from docs/SystemDesign/5-DataQuery/5-GroupByQuery.md
rename to docs/SystemDesign/5-DataQuery/6-GroupByQuery.md
diff --git a/docs/SystemDesign/5-DataQuery/6-LastQuery.md b/docs/SystemDesign/5-DataQuery/7-LastQuery.md
similarity index 100%
rename from docs/SystemDesign/5-DataQuery/6-LastQuery.md
rename to docs/SystemDesign/5-DataQuery/7-LastQuery.md
diff --git a/docs/SystemDesign/5-DataQuery/7-AlignByDeviceQuery.md b/docs/SystemDesign/5-DataQuery/8-AlignByDeviceQuery.md
similarity index 100%
rename from docs/SystemDesign/5-DataQuery/7-AlignByDeviceQuery.md
rename to docs/SystemDesign/5-DataQuery/8-AlignByDeviceQuery.md
diff --git a/docs/SystemDesign/5-DataQuery/9-FillFunction.md b/docs/SystemDesign/5-DataQuery/9-FillFunction.md
new file mode 100644
index 0000000..09769b6
--- /dev/null
+++ b/docs/SystemDesign/5-DataQuery/9-FillFunction.md
@@ -0,0 +1,149 @@
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+    
+        http://www.apache.org/licenses/LICENSE-2.0
+    
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+
+# Fill Function
+
+The main logic of Fill function is in FillQueryExecutor
+
+* org.apache.iotdb.db.query.executor.FillQueryExecutor
+
+Two fill functions are support in IoTDB, Previous Fill and Linear Fill. The logic of Linear Fill is very straightforward. We mainly highlight on introducing Previous Fill in this chapter.
+
+# Previous Fill
+
+The target of Previous Fill is to find out the time-value that has the largest timestamp, which is also smaller or equal to `queryTime`. The graph below displays one scenario of the function.
+```
+                                     |
++-------------------------+          |
+|     seq files           |          |
++-------------------------+          |
+                                     |
+            +---------------------------+
+            |     unseq files        |  |
+            +---------------------------+ 
+                                     |
+                                     |
+                                 queryTime
+```
+
+## Design principle
+In the real scenarios, the previous fill result may exist in a single page in tons of TsFiles. To accelerate the search procedure, **the key point** is to filter as many tsFiles out as possible.
+
+The main logic of TsFile filtering work is in `UnpackOverlappedUnseqFiles()`.
+
+## Find the "lower bound" from all the sequential files
+We first find out the "last point" of sequential files that satisfies fill queryTime. Since all the chunk data in sequential files are in decent order, this last point can be easily obtained by `retrieveValidLastPointFromSeqFiles()` function.
+
+After the above "last point " is found via `retrieveValidLastPointFromSeqFiles()`, the timestamp of this last point can be treated as a lower bound in the following searching. Only those points whose timestamps exceeds this lower bound are candidates to become the final result. 
+
+In the below example, the unseq file is not qualified to be processed as its end time is before "last point".
+
+```
+                        last point
+                              |       |
+            +---------------------------+
+            |   seq file      |       | |
+            +---------------------------+ 
+  +-------------------------+ |       |
+  |      unseq file         | |       |
+  +-------------------------+ |       |
+                              |       |
+                                      |
+                                queryTime
+```
+
+## Filter unseq files with lower bound
+The selecting of unseq files is in method `UnpackOverlappedUnseqFiles(long lBoundTime)`. All the unseq files are filtered by the parameter `lBoundTime`, and unpacked into Timeseries Metadata. We cache all the `TimeseriesMetadata` into `unseqTimeseriesMetadataList`. 
+
+Firstly the method selects the last unseq file that satisfies timeFilter. Its end time must be larger than `lBoundTime`, otherwise this file will be skipped. It is guaranteed that the rest files will cross the queryTime line, that is startTime <= queryTime and queryTime <= endTime. Then we can update the `lBoundTime` with the start time of the unpacked `TimeseriesMetadata`.
+
+In the below graph, the `lBoundTime` is updated with start time of unseq file in case1, and not updated in case2.
+```
+case1           case2
+  |              |                     |
+  |          +---------------------------+
+  |          |   |    unseq file       | |
+  |          +---------------------------+ 
+  |              |                     |
+  |              |                     |
+lBoundTime   lBoundTime            queryTime
+```
+
+```
+while (!unseqFileResource.isEmpty()) {
+  // The very end time of unseq files is smaller than lBoundTime,
+  // then skip all the rest unseq files
+  if (unseqFileResource.peek().getEndTimeMap().get(seriesPath.getDevice()) < lBoundTime) {
+    return;
+  }
+  TimeseriesMetadata timeseriesMetadata =
+      FileLoaderUtils.loadTimeSeriesMetadata(
+          unseqFileResource.poll(), seriesPath, context, timeFilter, allSensors);
+  if (timeseriesMetadata != null && timeseriesMetadata.getStatistics().canUseStatistics()
+      && lBoundTime <= timeseriesMetadata.getStatistics().getEndTime()) {
+    lBoundTime = Math.max(lBoundTime, timeseriesMetadata.getStatistics().getStartTime());
+    unseqTimeseriesMetadataList.add(timeseriesMetadata);
+    break;
+  }
+}
+```
+
+Next, the selected Timeseries Metadata could be used to find all the other overlapped unseq files. It should be noted that each time when a overlapped unseq file is added, the `lBoundTime` could be updated if the end time of this file satisfies `queryTime`
+
+```
+while (!unseqFileResource.isEmpty()
+        && (lBoundTime <= unseqFileResource.peek().getEndTimeMap().get(seriesPath.getDevice()))) {
+  TimeseriesMetadata timeseriesMetadata =
+      FileLoaderUtils.loadTimeSeriesMetadata(
+          unseqFileResource.poll(), seriesPath, context, timeFilter, allSensors);
+  unseqTimeseriesMetadataList.add(timeseriesMetadata);
+  // update lBoundTime if current unseq timeseriesMetadata's last point is a valid result
+  if (timeseriesMetadata.getStatistics().canUseStatistics()
+      && endtimeContainedByTimeFilter(timeseriesMetadata.getStatistics())) {
+    lBoundTime = Math.max(lBoundTime, timeseriesMetadata.getStatistics().getEndTime());
+  }
+}
+```
+
+## Compose the Previous Fill result
+
+The method `getFillResult()` will search among the sequential and un-sequential file to find the result. When searching in a chunk or a page, the statistic data should be utilized first.
+
+```
+public TimeValuePair getFillResult() throws IOException {
+    TimeValuePair lastPointResult = retrieveValidLastPointFromSeqFiles();
+    UnpackOverlappedUnseqFiles(lastPointResult.getTimestamp());
+    
+    long lastVersion = 0;
+    PriorityQueue<ChunkMetadata> sortedChunkMetatdataList = sortUnseqChunkMetadatasByEndtime();
+    while (!sortedChunkMetatdataList.isEmpty()
+        && lastPointResult.getTimestamp() <= sortedChunkMetatdataList.peek().getEndTime()) {
+      ChunkMetadata chunkMetadata = sortedChunkMetatdataList.poll();
+      TimeValuePair lastChunkPoint = getChunkLastPoint(chunkMetadata);
+      if (shouldUpdate(lastPointResult.getTimestamp(), lastVersion,
+          lastChunkPoint.getTimestamp(), chunkMetadata.getVersion())) {
+        lastPointResult = lastChunkPoint;
+        lastVersion = chunkMetadata.getVersion();
+      }
+    }
+    return lastPointResult;
+}
+```
diff --git a/docs/zh/SystemDesign/5-DataQuery/1-DataQuery.md b/docs/zh/SystemDesign/5-DataQuery/1-DataQuery.md
index 47cbc19..880ce68 100644
--- a/docs/zh/SystemDesign/5-DataQuery/1-DataQuery.md
+++ b/docs/zh/SystemDesign/5-DataQuery/1-DataQuery.md
@@ -35,9 +35,10 @@
 ## 相关文档
 
 * [基础查询组件](/zh/SystemDesign/5-DataQuery/2-SeriesReader.html)
-* [原始数据查询](/zh/SystemDesign/5-DataQuery/3-RawDataQuery.html)
-* [聚合查询](/zh/SystemDesign/5-DataQuery/4-AggregationQuery.html)
-* [降采样查询](/zh/SystemDesign/5-DataQuery/5-GroupByQuery.html)
-* [最近时间戳查询](/zh/SystemDesign/5-DataQuery/6-LastQuery.html)
-* [按设备对齐查询](/zh/SystemDesign/5-DataQuery/7-AlignByDeviceQuery.html)
-* [查询中的数据删改处理](/zh/SystemDesign/5-DataQuery/8-ModificationHandle.html)
+* [查询中的数据删改处理](/zh/SystemDesign/5-DataQuery/3-ModificationHandle.html)
+* [原始数据查询](/zh/SystemDesign/5-DataQuery/4-RawDataQuery.html)
+* [聚合查询](/zh/SystemDesign/5-DataQuery/5-AggregationQuery.html)
+* [降采样查询](/zh/SystemDesign/5-DataQuery/6-GroupByQuery.html)
+* [最近时间戳查询](/zh/SystemDesign/5-DataQuery/7-LastQuery.html)
+* [按设备对齐查询](/zh/SystemDesign/5-DataQuery/8-AlignByDeviceQuery.html)
+* [空值填充](/zh/SystemDesign/5-DataQuery/9-FillFunction.html)
diff --git a/docs/zh/SystemDesign/5-DataQuery/8-ModificationHandle.md b/docs/zh/SystemDesign/5-DataQuery/3-ModificationHandle.md
similarity index 100%
rename from docs/zh/SystemDesign/5-DataQuery/8-ModificationHandle.md
rename to docs/zh/SystemDesign/5-DataQuery/3-ModificationHandle.md
diff --git a/docs/zh/SystemDesign/5-DataQuery/3-RawDataQuery.md b/docs/zh/SystemDesign/5-DataQuery/4-RawDataQuery.md
similarity index 100%
rename from docs/zh/SystemDesign/5-DataQuery/3-RawDataQuery.md
rename to docs/zh/SystemDesign/5-DataQuery/4-RawDataQuery.md
diff --git a/docs/zh/SystemDesign/5-DataQuery/4-AggregationQuery.md b/docs/zh/SystemDesign/5-DataQuery/5-AggregationQuery.md
similarity index 100%
rename from docs/zh/SystemDesign/5-DataQuery/4-AggregationQuery.md
rename to docs/zh/SystemDesign/5-DataQuery/5-AggregationQuery.md
diff --git a/docs/zh/SystemDesign/5-DataQuery/5-GroupByQuery.md b/docs/zh/SystemDesign/5-DataQuery/6-GroupByQuery.md
similarity index 100%
rename from docs/zh/SystemDesign/5-DataQuery/5-GroupByQuery.md
rename to docs/zh/SystemDesign/5-DataQuery/6-GroupByQuery.md
diff --git a/docs/zh/SystemDesign/5-DataQuery/6-LastQuery.md b/docs/zh/SystemDesign/5-DataQuery/7-LastQuery.md
similarity index 100%
rename from docs/zh/SystemDesign/5-DataQuery/6-LastQuery.md
rename to docs/zh/SystemDesign/5-DataQuery/7-LastQuery.md
diff --git a/docs/zh/SystemDesign/5-DataQuery/7-AlignByDeviceQuery.md b/docs/zh/SystemDesign/5-DataQuery/8-AlignByDeviceQuery.md
similarity index 100%
rename from docs/zh/SystemDesign/5-DataQuery/7-AlignByDeviceQuery.md
rename to docs/zh/SystemDesign/5-DataQuery/8-AlignByDeviceQuery.md
diff --git a/docs/zh/SystemDesign/5-DataQuery/9-FillFunction.md b/docs/zh/SystemDesign/5-DataQuery/9-FillFunction.md
new file mode 100644
index 0000000..dd8292b
--- /dev/null
+++ b/docs/zh/SystemDesign/5-DataQuery/9-FillFunction.md
@@ -0,0 +1,148 @@
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+
+# 空值填充
+
+空值填充的主要逻辑在 FillQueryExecutor
+
+* org.apache.iotdb.db.query.executor.FillQueryExecutor
+
+IoTDB 中支持两种填充方式,Previous填充和Linear填充。Linear填充的实现逻辑较为简单,在此章中重点介绍Previous填充的实现逻辑。
+
+## Previous填充
+
+Previous填充是使用离查询时间戳最近且小于等于查询时间戳的值来进行填充的一种方式,下图展示了一种可能的填充情况。
+```
+                                     |
++-------------------------+          |
+|     seq files           |          |
++-------------------------+          |
+                                     |
+            +---------------------------+
+            |     unseq files        |  |
+            +---------------------------+ 
+                                     |
+                                     |
+                                 queryTime
+```
+
+## 设计原理
+
+在实际生产场景中,可能需要在大量的顺序和乱序TsFile中查找可用的填充值,因此解开大量TsFile文件会成为性能瓶颈。我们设计的思路在于尽可能的减少需要解开tsFile文件的个数,从而加速找到填充值这一过程。
+
+## 顺序文件查找"最近点"
+
+首先在顺序文件中查询满足条件的"最近点"。由于所有顺序文件及其所有包含的chunk数据都已经按照顺序排列,因此这个"最近点"可以通过`retrieveValidLastPointFromSeqFiles()`方法很容易找到。
+
+这个找到的"最近点"是可以成为Previous填充的最终值的,因此它在接下来的搜索中能够被用来作为下界来寻找其他更好的的填充值。接下来只有那些时间戳大于这个下界的点才是Previous填充的结果值。
+
+下例中的unseq 文件由于其最大值没有超过"最近点",因此不需要再进一步搜索。
+```
+                        last point
+                              |       |
+            +---------------------------+
+            |   seq file      |       | |
+            +---------------------------+ 
+  +-------------------------+ |       |
+  |      unseq file         | |       |
+  +-------------------------+ |       |
+                              |       |
+                                      |
+                                queryTime
+```
+
+## 筛选乱序文件
+
+筛选并解开乱序文件的逻辑在成员函数`UnpackOverlappedUnseqFiles(long lBoundTime)`中,该方法接受一个下界参数,将满足要求的乱序文件解开且把它们的TimeseriesMetadata结构存入`unseqTimeseriesMetadataList`中。
+
+`UnpackOverlappedUnseqFiles(long lBoundTime)`方法首先用 `lBoundTime`排除掉不满足要求的乱序文件,剩下被筛选后的乱序文件都一定会包含`queryTime`时间戳,即startTime <= queryTime and queryTime <= endTime。如果乱序文件的start time大于`lBoundTime`,更新`lBoundTime`。
+
+下图中,case 1中的`lBoundTime`将会被更新,而case 2中的则不会被更新。
+```
+case1           case2
+  |              |                     |
+  |          +---------------------------+
+  |          |   |    unseq file       | |
+  |          +---------------------------+ 
+  |              |                     |
+  |              |                     |
+lBoundTime   lBoundTime            queryTime
+```
+
+```
+while (!unseqFileResource.isEmpty()) {
+  // The very end time of unseq files is smaller than lBoundTime,
+  // then skip all the rest unseq files
+  if (unseqFileResource.peek().getEndTimeMap().get(seriesPath.getDevice()) < lBoundTime) {
+    return;
+  }
+  TimeseriesMetadata timeseriesMetadata =
+      FileLoaderUtils.loadTimeSeriesMetadata(
+          unseqFileResource.poll(), seriesPath, context, timeFilter, allSensors);
+  if (timeseriesMetadata != null && timeseriesMetadata.getStatistics().canUseStatistics()
+      && lBoundTime <= timeseriesMetadata.getStatistics().getEndTime()) {
+    lBoundTime = Math.max(lBoundTime, timeseriesMetadata.getStatistics().getStartTime());
+    unseqTimeseriesMetadataList.add(timeseriesMetadata);
+    break;
+  }
+}
+```
+
+接下来我们可以使用得到的Timeseries Metadata来查找所有其他重叠的乱序文件。需要注意的依旧是当一个重叠的乱序文件被找到后,需要按情况更新`lBoundTime`。
+
+```
+while (!unseqFileResource.isEmpty()
+        && (lBoundTime <= unseqFileResource.peek().getEndTimeMap().get(seriesPath.getDevice()))) {
+  TimeseriesMetadata timeseriesMetadata =
+      FileLoaderUtils.loadTimeSeriesMetadata(
+          unseqFileResource.poll(), seriesPath, context, timeFilter, allSensors);
+  unseqTimeseriesMetadataList.add(timeseriesMetadata);
+  // update lBoundTime if current unseq timeseriesMetadata's last point is a valid result
+  if (timeseriesMetadata.getStatistics().canUseStatistics()
+      && endtimeContainedByTimeFilter(timeseriesMetadata.getStatistics())) {
+    lBoundTime = Math.max(lBoundTime, timeseriesMetadata.getStatistics().getEndTime());
+  }
+}
+```
+
+## 组合最终结果
+
+最终结果在方法`getFillResult()` 中生成。
+```
+public TimeValuePair getFillResult() throws IOException {
+    TimeValuePair lastPointResult = retrieveValidLastPointFromSeqFiles();
+    UnpackOverlappedUnseqFiles(lastPointResult.getTimestamp());
+    
+    long lastVersion = 0;
+    PriorityQueue<ChunkMetadata> sortedChunkMetatdataList = sortUnseqChunkMetadatasByEndtime();
+    while (!sortedChunkMetatdataList.isEmpty()
+        && lastPointResult.getTimestamp() <= sortedChunkMetatdataList.peek().getEndTime()) {
+      ChunkMetadata chunkMetadata = sortedChunkMetatdataList.poll();
+      TimeValuePair lastChunkPoint = getChunkLastPoint(chunkMetadata);
+      if (shouldUpdate(lastPointResult.getTimestamp(), lastVersion,
+          lastChunkPoint.getTimestamp(), chunkMetadata.getVersion())) {
+        lastPointResult = lastChunkPoint;
+        lastVersion = chunkMetadata.getVersion();
+      }
+    }
+    return lastPointResult;
+}
+```
diff --git a/site/src/main/.vuepress/config.js b/site/src/main/.vuepress/config.js
index 9eb184f..538fa9f 100644
--- a/site/src/main/.vuepress/config.js
+++ b/site/src/main/.vuepress/config.js
@@ -435,12 +435,13 @@ var config = {
 						children: [
 							['5-DataQuery/1-DataQuery','DataQuery'],
 							['5-DataQuery/2-SeriesReader','SeriesReader'],
-							['5-DataQuery/3-RawDataQuery','RawDataQuery'],
-							['5-DataQuery/4-AggregationQuery','AggregationQuery'],
-							['5-DataQuery/5-GroupByQuery','GroupByQuery'],
-							['5-DataQuery/6-LastQuery','LastQuery'],
-							['5-DataQuery/7-AlignByDeviceQuery','AlignByDeviceQuery'],
-							['5-DataQuery/8-ModificationHandle','ModificationHandle']
+							['5-DataQuery/3-ModificationHandle','ModificationHandle'],
+							['5-DataQuery/4-RawDataQuery','RawDataQuery'],
+							['5-DataQuery/5-AggregationQuery','AggregationQuery'],
+							['5-DataQuery/6-GroupByQuery','GroupByQuery'],
+							['5-DataQuery/7-LastQuery','LastQuery'],
+							['5-DataQuery/8-AlignByDeviceQuery','AlignByDeviceQuery'],
+							['5-DataQuery/9-FillFunction','FillFunction']
 						]
 					},
 					{
@@ -844,12 +845,13 @@ var config = {
 						children: [
 							['5-DataQuery/1-DataQuery','数据查询'],
 							['5-DataQuery/2-SeriesReader','查询基础组件'],
-							['5-DataQuery/3-RawDataQuery','原始数据查询'],
-							['5-DataQuery/4-AggregationQuery','聚合查询'],
-							['5-DataQuery/5-GroupByQuery','降采样查询'],
-							['5-DataQuery/6-LastQuery','最近时间戳 Last 查询'],
-							['5-DataQuery/7-AlignByDeviceQuery','按设备对齐查询'],
-							['5-DataQuery/8-ModificationHandle','查询中的数据修改处理']
+							['5-DataQuery/3-ModificationHandle','查询中的数据修改处理'],
+							['5-DataQuery/4-RawDataQuery','原始数据查询'],
+							['5-DataQuery/5-AggregationQuery','聚合查询'],
+							['5-DataQuery/6-GroupByQuery','降采样查询'],
+							['5-DataQuery/7-LastQuery','最近时间戳 Last 查询'],
+							['5-DataQuery/8-AlignByDeviceQuery','按设备对齐查询'],
+							['5-DataQuery/9-FillFunction','空值填充']
 						]
 					},
 					{
@@ -886,4 +888,4 @@ var config = {
   }
   
   module.exports = config
-  
\ No newline at end of file
+