document-dataply 0.0.10-alpha.6 → 0.0.10-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js
CHANGED
|
@@ -10482,7 +10482,7 @@ var SELECTIVITY = {
|
|
|
10482
10482
|
/** FTS 통계 없을 때 보수적 추정 */
|
|
10483
10483
|
FTS_DEFAULT: 0.5,
|
|
10484
10484
|
/** 정렬 비용 가중치 (orderBy 미지원 시) */
|
|
10485
|
-
SORT_PENALTY: 0.
|
|
10485
|
+
SORT_PENALTY: 0.5,
|
|
10486
10486
|
/** 인메모리 정렬이 유의미해지는 임계 문서 수 */
|
|
10487
10487
|
SORT_THRESHOLD: 1e4
|
|
10488
10488
|
};
|
|
@@ -10668,9 +10668,12 @@ var Optimizer = class {
|
|
|
10668
10668
|
* 비용 계산: effectiveScanCost + sortPenalty
|
|
10669
10669
|
* - effectiveScanCost: 인덱스 순서 지원 + limit 존재 시 조기 종료 이점 반영
|
|
10670
10670
|
* - sortPenalty: 인메모리 정렬의 절대 문서 수 기반 비용
|
|
10671
|
+
* - hasUncoveredFilters: 드라이버가 커버하지 못하는 비-FTS 필터 존재 여부
|
|
10672
|
+
* true일 경우 topK/N 조기 종료를 적용하지 않음
|
|
10673
|
+
* (uncovered 필터가 행을 탈락시킬 수 있어 topK개 이상 스캔 필요)
|
|
10671
10674
|
*/
|
|
10672
|
-
calculateCost(selectivity, isIndexOrderSupported, orderByField, N, topK) {
|
|
10673
|
-
const effectiveScanCost = isIndexOrderSupported && isFinite(topK) && N > 0 ? Math.min(topK / N, selectivity) : selectivity;
|
|
10675
|
+
calculateCost(selectivity, isIndexOrderSupported, orderByField, N, topK, hasUncoveredFilters = false) {
|
|
10676
|
+
const effectiveScanCost = isIndexOrderSupported && isFinite(topK) && N > 0 && !hasUncoveredFilters ? Math.min(topK / N, selectivity) : selectivity;
|
|
10674
10677
|
const estimatedSortDocs = selectivity * N;
|
|
10675
10678
|
const sortPenalty = orderByField && !isIndexOrderSupported ? Math.min(estimatedSortDocs / SELECTIVITY.SORT_THRESHOLD, 1) * SELECTIVITY.SORT_PENALTY : 0;
|
|
10676
10679
|
return effectiveScanCost + sortPenalty;
|
|
@@ -10699,9 +10702,19 @@ var Optimizer = class {
|
|
|
10699
10702
|
orderByField
|
|
10700
10703
|
);
|
|
10701
10704
|
if (candidate) {
|
|
10705
|
+
const hasUncoveredFilters = ![...queryFields].every(
|
|
10706
|
+
(f) => candidate.coveredFields.includes(f)
|
|
10707
|
+
);
|
|
10702
10708
|
candidates.push({
|
|
10703
10709
|
...candidate,
|
|
10704
|
-
cost: this.calculateCost(
|
|
10710
|
+
cost: this.calculateCost(
|
|
10711
|
+
candidate.selectivity,
|
|
10712
|
+
candidate.isIndexOrderSupported,
|
|
10713
|
+
orderByField,
|
|
10714
|
+
N,
|
|
10715
|
+
topK,
|
|
10716
|
+
hasUncoveredFilters
|
|
10717
|
+
)
|
|
10705
10718
|
});
|
|
10706
10719
|
}
|
|
10707
10720
|
} else if (config.type === "fts") {
|
|
@@ -10716,7 +10729,14 @@ var Optimizer = class {
|
|
|
10716
10729
|
if (candidate) {
|
|
10717
10730
|
candidates.push({
|
|
10718
10731
|
...candidate,
|
|
10719
|
-
cost: this.calculateCost(
|
|
10732
|
+
cost: this.calculateCost(
|
|
10733
|
+
candidate.selectivity,
|
|
10734
|
+
candidate.isIndexOrderSupported,
|
|
10735
|
+
orderByField,
|
|
10736
|
+
N,
|
|
10737
|
+
topK,
|
|
10738
|
+
true
|
|
10739
|
+
)
|
|
10720
10740
|
});
|
|
10721
10741
|
}
|
|
10722
10742
|
}
|
|
@@ -11035,12 +11055,24 @@ var QueryManager = class {
|
|
|
11035
11055
|
}
|
|
11036
11056
|
return true;
|
|
11037
11057
|
}
|
|
11038
|
-
|
|
11039
|
-
|
|
11040
|
-
|
|
11041
|
-
|
|
11042
|
-
|
|
11043
|
-
|
|
11058
|
+
/**
|
|
11059
|
+
* 최적화 공식: x = x * Math.sqrt(z / n)
|
|
11060
|
+
* @param currentChunkSize 현재 청크 크기
|
|
11061
|
+
* @param matchedCount 매칭된 문서 개수
|
|
11062
|
+
* @param limit 최대 문서 개수
|
|
11063
|
+
* @param chunkTotalSize 청크 내 문서 총 크기
|
|
11064
|
+
* @returns
|
|
11065
|
+
*/
|
|
11066
|
+
adjustChunkSize(currentChunkSize, matchedCount, limit, chunkTotalSize) {
|
|
11067
|
+
if (matchedCount <= 0 || chunkTotalSize <= 0) return currentChunkSize;
|
|
11068
|
+
const n = Math.max(matchedCount, 1);
|
|
11069
|
+
const z = isFinite(limit) ? limit : currentChunkSize * 10;
|
|
11070
|
+
const nextChunkSize = Math.ceil(currentChunkSize * Math.sqrt(z / n));
|
|
11071
|
+
const { smallChunkSize } = this.getFreeMemoryChunkSize();
|
|
11072
|
+
const avgDocSize = chunkTotalSize / currentChunkSize;
|
|
11073
|
+
const maxSafeChunkSize = Math.max(Math.floor(smallChunkSize / avgDocSize), 20);
|
|
11074
|
+
const finalChunkSize = Math.max(Math.min(nextChunkSize, maxSafeChunkSize), 20);
|
|
11075
|
+
return finalChunkSize;
|
|
11044
11076
|
}
|
|
11045
11077
|
async *processChunkedKeysWithVerify(keysStream, startIdx, initialChunkSize, limit, ftsConditions, compositeVerifyConditions, others, tx) {
|
|
11046
11078
|
const verifyOthers = others.filter((o) => !o.isFtsMatch);
|
|
@@ -11056,6 +11088,7 @@ var QueryManager = class {
|
|
|
11056
11088
|
let chunk = [];
|
|
11057
11089
|
let chunkSize = 0;
|
|
11058
11090
|
let dropped = 0;
|
|
11091
|
+
let nAccumulated = 0;
|
|
11059
11092
|
const processChunk = async (pks) => {
|
|
11060
11093
|
const docs = [];
|
|
11061
11094
|
const rawResults = await this.api.selectMany(new Float64Array(pks), false, tx);
|
|
@@ -11107,8 +11140,9 @@ var QueryManager = class {
|
|
|
11107
11140
|
}
|
|
11108
11141
|
docs.push(doc);
|
|
11109
11142
|
}
|
|
11143
|
+
nAccumulated += docs.length;
|
|
11110
11144
|
if (!isReadQuotaLimited) {
|
|
11111
|
-
currentChunkSize = this.adjustChunkSize(currentChunkSize, chunkTotalSize);
|
|
11145
|
+
currentChunkSize = this.adjustChunkSize(currentChunkSize, nAccumulated, limit, chunkTotalSize);
|
|
11112
11146
|
}
|
|
11113
11147
|
return docs;
|
|
11114
11148
|
};
|
|
@@ -38,6 +38,9 @@ export declare class Optimizer<T extends Record<string, any>> {
|
|
|
38
38
|
* 비용 계산: effectiveScanCost + sortPenalty
|
|
39
39
|
* - effectiveScanCost: 인덱스 순서 지원 + limit 존재 시 조기 종료 이점 반영
|
|
40
40
|
* - sortPenalty: 인메모리 정렬의 절대 문서 수 기반 비용
|
|
41
|
+
* - hasUncoveredFilters: 드라이버가 커버하지 못하는 비-FTS 필터 존재 여부
|
|
42
|
+
* true일 경우 topK/N 조기 종료를 적용하지 않음
|
|
43
|
+
* (uncovered 필터가 행을 탈락시킬 수 있어 topK개 이상 스캔 필요)
|
|
41
44
|
*/
|
|
42
45
|
private calculateCost;
|
|
43
46
|
/**
|
|
@@ -45,7 +45,15 @@ export declare class QueryManager<T extends DocumentJSON> {
|
|
|
45
45
|
condition: any;
|
|
46
46
|
}[]): boolean;
|
|
47
47
|
verifyValue(value: Primitive, condition: any): boolean;
|
|
48
|
-
|
|
48
|
+
/**
|
|
49
|
+
* 최적화 공식: x = x * Math.sqrt(z / n)
|
|
50
|
+
* @param currentChunkSize 현재 청크 크기
|
|
51
|
+
* @param matchedCount 매칭된 문서 개수
|
|
52
|
+
* @param limit 최대 문서 개수
|
|
53
|
+
* @param chunkTotalSize 청크 내 문서 총 크기
|
|
54
|
+
* @returns
|
|
55
|
+
*/
|
|
56
|
+
adjustChunkSize(currentChunkSize: number, matchedCount: number, limit: number, chunkTotalSize: number): number;
|
|
49
57
|
processChunkedKeysWithVerify(keysStream: AsyncIterableIterator<number>, startIdx: number, initialChunkSize: number, limit: number, ftsConditions: {
|
|
50
58
|
field: string;
|
|
51
59
|
matchTokens: string[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "document-dataply",
|
|
3
|
-
"version": "0.0.10-alpha.
|
|
3
|
+
"version": "0.0.10-alpha.7",
|
|
4
4
|
"description": "Simple and powerful JSON document database supporting complex queries and flexible indexing policies.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "izure <admin@izure.org>",
|