グローバルのCachéビットマップインデックス

CachéオブジェクトDBMSは、ビットマップインデックスとビットスライスインデックスをサポートしています。 Cachéクラスでの使用は非常に簡単です。インデックスの説明でBitmapまたはBitslice属性を指定するだけで十分であり、一部のSQLクエリのパフォーマンスは劇的に向上します。 しかし、それはどのように機能しますか?

この記事では、ビットマップインデックスの構造、任意のグローバル構造でのビットマップインデックスの作成方法、ビットロジック関数の使用方法、およびCachéでNoSQLを実行する際の効果的な使用方法について説明します。



事前オブジェクト時間以来、グローバルで関心のあるレコードを迅速に検索するためのアプリケーションを開発するとき、最も頻繁にフォームのインデックスが構築されました



セット ^インデックス( "Property" 、 value 、 id )= ""



このようなインデックスを使用すると、対象のプロパティに特定の値があるレコードを簡単かつ迅速に検索できます。



set id = "" for set id = $ order (^ Index( "Property" 、 value 、 id )) quit : id = "" write id、!



Propertyプロパティの値がvalueであるすべてのレコードの識別子を提供します。たとえば、次のコードを使用して、このプロパティ値を持つレコードの存在を確認できます。



if $ data (^ Index( "Property" 、 value ))> 1 {

"id" _ $ order (^ Index( "Property" 、 value 、 "" ))を 書き込み ます _ "with" _ value _ "exists" }

その他 {

「次のものがあるレコード」 _ 値 _ 「存在しない 」を 書き込む }



「I」ロジックによって結合された複数の条件を同時に満たすレコードを効率的に検索するためのアルゴリズムを考案することは難しくありません。 しかし、より複雑なクエリの場合は、より複雑なアルゴリズムを開発(およびデバッグ)するか、データベース内のすべてのレコードを直接列挙するためにインデックスの使用を放棄する必要がありました。



革命的な変更は、Cachéでの本格的なビット関数の出現でした。 $ bit ()、 $ bitlogic ()、 $ bitfind ()、 $ bitcount ()です。 次の形式のビットマップインデックスを構築できます。



set $ bit (^ Index( "Property" 、 value )、 id )= 1



もちろん、ビット文字列の長さは256Kに制限されているため、実際のアプリケーションではビットマップインデックスは1ビット文字列ではなく配列に配置する必要があります。

$ bitlogic()関数は、任意の興味深いクエリを満たすレコードのサンプルに対応するインデックスから結果のビットマップインデックスを簡単に形成することを可能にし、$ bitcount()はサンプルに含まれるレコードの数を決定し、$ bitfind()は結果のサンプル。



たとえば、「Pr1」プロパティの値が「A」または「B」で、「Pr2」プロパティの値が「C」であるレコードを収集します。



set ^ mtemp.resbitmap = $ bitlogic (^ Index( "Pr1" 、 "A" )| ^ Index( "Pr1" 、 "B" ))

set ^ mtemp.resbitmap = $ bitlogic (^ mtemp.resbitmap&^ Index( "Pr2" 、 "C" ))



そしてそれらにIDを与えます:



if ' $ bitcount(^ mtemp.resbitmap) write "No records found" 、!

それ以外の場合は 、set id = $ bitfind (^ mtemp.resbitmap、1、 id )の 場合、 set id = 0 quit : ' id write id 、!



これは、Cachéのビット関数から絞り込めるだけではありません。 グループ化関数の値(合計、算術平均、最小、最大)をすべて同じように計算するには、サンプルに含まれるすべてのレコードを並べ替える必要がありましたが、十分なサンプルサイズでは高速ではありませんでした。 ただし、ビットマップインデックスの構造を少し変更すると、プロパティ値が整数または固定小数点の場合、この手順も大幅に高速化されます。

この変更の本質は、プロパティ値の各ビットに個別のビットマップインデックスを構築することです。 このような構造はビットスライスと呼ばれます。



set $ bit (^ Index( "Property" 、 N )、 id )= NthBitOfValue



実際にも、ビット文字列の代わりに配列が使用されます。

ビットスライスを使用する場合、たとえば「より多く」または「より少ない」制限を検索するなど、少し複雑になりますが、グループ化関数の計算で得られるメリットはこの不便さを大きく上回ります。 実際、選択したレコードの対象プロパティの値の合計を計算するために、レコードを循環する必要はなくなりました。 すべてのビットの結果のビットマップインデックスの対応する重み$ bitcount()で対象のプロパティの値を合計するだけで十分です。 十分なサンプルサイズがあれば、パフォーマンスの向上は、誇張と呼ばれる誇張なしで実現できます。



クラスコード
///ビットマップおよびビットスライスインデックスを作成および操作するための一連のメソッド

///

///ビットマップインデックスの構造

///配列(値)の形式の配列、その要素は

///レコード番号に対応する位置に1を含むビット文字列、

///いくつかのパラメータが値valueをとる、

///最大長$$$ MAXBITLENGTHの文字列の配列に分割

///レコード番号-1から、配列要素-0から、

///(以降、簡潔にするため、ビットマップ)。

///充填の例

///エントリにidfactパラメータ番号を持たせますparはvalです

/// idf0 = idfact-1 \ $$$ MAXBITLENGTHを設定、idf1 = idfact-1#$$$ MAXBITLENGTH + 1

/// $ビットを設定(^ BM( "I"、par、val、idf0)、idf1)= 1

/// $ビットを設定(^ BM( "EXIST"、idf0)、idf1)= 1

///まず、既存のエントリのインデックスが便利です。

///論理削除を簡単に実行できます。次に、

///を使用せずにリポジトリ内のレコード数を検索できるようにします

///他の構造へのアクセス、これは正しいために必要です

/// BMNotプロシージャの操作(以下を参照)

/// beatleysインデックスの構造:

///ビットマップインデックスの配列。 配列の最初の要素-文字インデックス

///値、2番目—値の最下位ビットのインデックス(1/0)、3番目—

///最後から2番目のビットのインデックス(2/0)など

///

///充填の例

///エントリ番号idfactパラメータparに整数を持たせる

/// valの値

/// idf0 = idfact-1 \ $$$ MAXBITLENGTHを設定、idf1 = idfact-1#$$$ MAXBITLENGTH + 1

/// val = $$ CvtToBin(val)を設定

/// for ix = 1:1:$ length(val)set:$ extract(val、ix)$ bit(^ BM( "S"、par、ix、idf0)、idf1)= 1

///壊滅的な落下を避けるための大量充填時

///パフォーマンス、対応するフラグメントをオーバーレイすることをお勧めします

///関数のコード$ sortbegin(^ BM)および$ sortend(^ BM)

///指定された制限に応じたファクトの選択および受信した計算用

///グループ化関数「sum」、「maximum」、および「minimum」のサンプル

///関数BSSum()、BSMax()およびBSMin()が対象

クラスUser.BitMapSlice Extends%RegisteredObject [ ProcedureBlock ]

{



///ビットマップとビットスライスを保存するグローバルな名前($ na)

///デフォルト値は「^ BM」です

プロパティ BMGLOB As%String ( TRUNCATE = 1 )[ InitialExpression = "^ BM" ];



///使用する$ビット文字列の最大長

パラメーター MAXBITLENGTH = 64000 ;



///グローバルグローバルサブノードの名前($ na())を作成して返します

///中間ビットマップを保存するため

ClassMethod GetNewTMP() As%文字列

{

quit $ name (^ CacheTemp( "BM" 、 $ job _ $ zutil (110)、 $ increment (^ CacheTemp( "BM" 、 $ job _ $ zutil (110)))))

}



///このプロセスによって作成されたすべての一時的なサブノードを削除します

ClassMethod KillAllTMP()

{

kill ^ CacheTemp( "BM" 、 $ job _ $ zutil (110)) quit

}



///ビットマップの操作

///以下、柔軟性、ビットインデックス、

///配列とスライスは名前で渡される($ na())

///

/// posに続く位置を1ビットで見つける

/// bm-名前で渡されるビットマップ

メソッド BMOrder( bm As%String 、 pos As%String ) As%String

{

set sub = pos \ .. #MAXBITLENGTH 、 ix = $ bitfind ( $ get (@ bm @( sub ))、1、 pos #.. #MAXBITLENGTH +1)

quit : ix sub * .. #MAXBITLENGTH + ix

set sub = $ order (@ bm @( sub )) quit : ' sub set ix = $ bitfind ( $ get (@ bm @( sub ))、1) quit : ix

quit : ix sub * .. #MAXBITLENGTH + ix

「」を 終了

}



/// bmdest = bmdest&bmsrc

メソッド BMAnd( bmdest As%String 、 bmsrc As%String )

{

set sub1 = $ order (@ bmdest @( $ char (0))、-1)、 sub = $ order (@ bmsrc @( $ char (0))、-1)

セット : sub < sub1 sub = sub1

for ix = 0:1: sub set : $ data (@ bmdest @( ix ))& $ data (@ bmsrc @( ix ))@ bmdest @( ix )= $ bitlogic (@ bmdest @( ix )&@ bmsrc @( ix )) kill : ' $ data (@ bmsrc @( ix ))@ bmdest @( ix )

やめる

}



/// bmdest = bmdest | bmsrc

メソッド BMOr( bmdest As%String 、 bmsrc As%String )

{

set sub1 = $ order (@ bmdest @( $ char (0))、-1)、 sub = $ order (@ bmsrc @( $ char (0))、-1)

セット : sub < sub1 sub = sub1

for ix = 0:1: sub set : $ data (@ bmsrc @( ix ))@ bmdest @( ix )= $ select ( $ data (@ bmdest @( ix )): $ bitlogic (@ bmdest @( ix ) | @ bmsrc @( ix ))、1:@ bmsrc @( ix ))

やめる

}



メソッド BMNot( bm As%String )

{

set maxblk = $ order (@(.. BMGLOB )@( "EXIST" 、 "" )、-1)、 blklen = $ bitcount (@(.. BMGLOB )@( "EXIST" 、 maxblk ))

for ix = maxblk :-1:0 set blk = $ get (@ bm @( ix )) set : $ bitcount ( blk )< blklen $ bit ( blk 、 blklen )= 0 set @ bm @( ix )= $ bitlogic ( 〜blk )、 blklen = .. #MAXBITLENGTH

do .. BMAnd ( bm 、 $ name (@(.. BMGLOB )@( "EXIST" ))))

やめる

}



///配列内の単位ビットの数を返します

メソッド BMCount( bm As%String ) As%Integer

{

ix = "" 、 bmcret = 0に設定

set ix = $ order (@ bm @( ix )) quit : ix '= + ix set bmcret = bmcret + $ bitcount (@ bm @( ix )、1)

bmcretを 終了

}



///ビットマップインデックスvbmsrcから選択をbmdestビットマップに配置し、

///パラメータ値はvalです

///

メソッド BMEq( bmdest As%String 、 vbmsrc As%String 、 val As%String )

{

kill @ bmdest merge @ bmdest = @ vbmsrc @( val )

やめる

}



///ビットマップインデックスvbmsrcから選択をbmdestビットマップに配置し、

///パラメータ値がvalと等しくない場合

メソッド BMNe( bmdest As%String 、 vbmsrc As%String 、 val As%String )

{

do .. BMEq ( bmdest 、 vbmsrc 、 val ) do .. BMNot ( bmdest )

やめる

}



///ビットマップインデックスvbmsrcから選択をbmdestビットマップに配置し、

///パラメータ値が小さい(ソートされた)val

/// bmdest:= U(vbmsrc(v):v <val)

メソッド BMLt( bmdest As%String 、 vbmsrc As%String 、 val As%String )

{

kill @ bmdest set ix = val

set ix = $ order (@ vbmsrc @( ix )、-1) quit : ix = "" do .. BMOr ( bmdest 、 $ name (@ vbmsrc @( ix )))

やめる

}



/// BMLt()に似ていますが、「より小さいか等しい」

メソッド BMLe( bmdest As%String 、 vbmsrc As%String 、 value As%String )

{

kill @ bmdest merge @ bmdest = @ vbmsrc @( val ) set ix = val

set ix = $ order (@ vbmsrc @( ix )、-1) quit : ix = "" do .. BMOr ( bmdest 、 $ name (@ vbmsrc @( ix )))

やめる

}



/// BMLeに似ていますが、「以上」

メソッド BMGe( bmdest As%String 、 vbmsrc As%String 、 val As%String )

{

kill @ bmdest merge @ bmdest = @ vbmsrc @( val ) set ix = val

set ix = $ order (@ vbmsrc @( ix )) quit : ix = "" do .. BMOr ( bmdest 、 $ name (@ vbmsrc @( ix ))))

やめる

}



///同様に、min以上max以下の値

メソッド BMGeLe( bmdest As%String 、 vbmsrc As%String 、 min As%String 、 max As%String )

{

kill @ bmdest merge @ bmdest = @ vbmsrc @( min ) set ix = min

set ix = $ order (@ vbmsrc @( ix )) quit : ix ]] max quit : ix = "" do .. BMOr ( bmdest 、 $ name (@ vbmsrc @( ix ))))

やめる

}



/// BMGe()に似ていますが、「厳密に大きい」

メソッド BMGt( bmdest As%String 、 vbmsrc As%String 、 val As%String )

{

kill @ bmdest set ix = val

set ix = $ order (@ vbmsrc @( ix )) quit : ix = "" do .. BMOr ( bmdest 、 $ name (@ vbmsrc @( ix ))))

やめる

}



///同様に、minより大きくmaxより小さい値

メソッド BMGtLt( bmdest As%String 、 vbmsrc As%String 、 min As%String 、 max As%String )

{

kill @ bmdest set ix = min

set ix = $ order (@ vbmsrc @( ix )) quit : max ']] ix quit : ix = "" do .. BMOr ( bmdest 、 $ name (@ vbmsrc @( ix )))

やめる

}



///同様に、min以上max以下の値

メソッド BMGeLt( bmdest As%String 、 vbmsrc As%String 、 min As%String 、 max As%String )

{

kill @ bmdest merge @ bmdest = @ vbmsrc @( min ) set ix = min

set ix = $ order (@ vbmsrc @( ix )) quit : max ']] ix quit : ix = "" do .. BMOr ( bmdest 、 $ name (@ vbmsrc @( ix )))

やめる

}



///同様に、minより大きくmax以下の値

メソッド BMGtLe( bmdest As%String 、 vbmsrc As%String 、 min As%String 、 max As%String )

{

kill @ bmdest set ix = min

set ix = $ order (@ vbmsrc @( ix )) quit : ix ]] max quit : ix = "" do .. BMOr ( bmdest 、 $ name (@ vbmsrc @( ix ))))

やめる

}



///ビットスライスデータの操作

///整数値をテキストビット文字列に変換します

/// {sign、1,2,4、...、2 ** N}

ClassMethod CvtToBin( value As%Integer ) As%String

{

設定 値 = $ fnumber (+ value 、 "" 、0)、 res =( value <0)

for quit : ' value set res = res _( value #2)、 value = value \ 2

解像度を やめる

}



/// $ lbビットリスト(符号、1、2、4、... 2 ** N)を整数に変換します

ClassMethod CvtFromSlice( slice As%String ) As%整数

{

res = 0に 設定

for i = $ listlength ( slice ):-1:2 set res = res + res set res = res + $ listget ( slice 、 i 、0)

quit $ select ( $ listget ( slice ):- res 、1: res )

}



/// vbs bitliceのpos位置からビットをリストに入れます($ lb())

メソッド GetSlice( vbs As%String 、 pos As%Integer ) As%String

{

set sub = pos \ .. # MAXBITLENGTH 、 ix = pos -1#.. #MAXBITLENGTH +1

for i = 1:1: $ order (@ vbs @( "" )、-1) set $ list ( slice 、 i )= $ bit ( $ get (@ vbs @( i 、 sub )))、 ix )

スライスを 終了

}



/// bmdestビット配列にvbsビットスライスインデックスからのサンプルを配置し、

///パラメータ値はvalです

メソッド BSEq( bmdest As%String 、 vbs As%String 、 val As%Integer )

{

set bswork = .. GetNewTMP () set vbit = .. CvtToBin ( val )

kill @ bmdest merge @ bmdest = @(.. BMGLOB )@( "EXIST" )

set maxbit = $ order (@ vbs @( "" )、-1) set : maxbit < $ length ( vbit ) maxbit = $ length ( vbit )

for ix = 1:1: maxbit kill @ bswork merge @ bswork = @ vbs @( ix ) do : ' $ extract ( vbit 、 ix ).. BMNot ( bswork ) do .. BMAnd ( bmdest 、 bswork )

@bswork quitを終了

}



/// bmdestビット配列にvbsビットスライスインデックスからのサンプルを配置し、

///パラメータの値がval以上の場合

メソッド BSGe( bmdest As%String 、 vbs As%String 、 val As%Integer )

{

do .. BSLt ( bmdest 、 vbs 、 val )、.. BMNot ( bmdest ) quit

}



/// bmdestビット配列にvbsビットスライスインデックスからのサンプルを配置し、

///パラメータ値がvalと等しくない場合

メソッド BSNe( bmdest As%String 、 vbs As%String 、 val As%Integer )

{

do .. BSEq ( bmdest 、 vbs 、 val )、.. BMNot ( bmdest )

やめる

}



/// bmdestビット配列にvbsビットスライスインデックスからのサンプルを配置し、

///パラメータ値がvalより大きい場合

///

メソッド BSGt( bmdest As%String 、 vbs As%String 、 val As%Integer )

{

do .. BSLe ( bmdest 、 vbs 、 val )、.. BMNot ( bmdest ) quit

}



/// bmdestビット配列にvbsビットスライスインデックスからのサンプルを配置し、

///パラメータの符号は符号です(ゼロは正と見なされます)

メソッド BSSign( bmdest As%String 、 vbs As%String 、 sign As%Integer )

{

set bswork = .. GetNewTMP () kill @ bmdest

merge @ bmdest = @(.. BMGLOB )@( "EXIST" )、@ bswork = @ vbs @(1)

do : $ get ( sign ) '<0 .. BMNot ( bswork ) do .. BMAnd ( bmdest 、 bswork )

@bswork quitを終了

}



/// bmdestビット配列にvbsビットスライスインデックスからのサンプルを配置し、

///パラメータ値がval以下の場合

メソッド BSLe( bmdest As%String 、 vbs As%String 、 val As%Integer )

{

tmpLe = .. GetNewTMP ()を 設定し ます

do .. BSLtAbs ( bmdest 、 vbs 、 val )、.. BSSign ( tmpLe 、 vbs 、-1)

if val '<0 do .. BMOr ( bmdest 、 tmpLe )、.. BSEq ( tmpLe 、 vbs 、 val )、.. BMOr ( bmdest 、 tmpLe ) if 1

それ以外の場合 .. BMNot ( bmdest )、.. BMAnd ( bmdest 、 tmpLe )

kill @ tmpLe quit

}



/// bmdestビット配列にvbsビットスライスインデックスからのサンプルを配置し、

///パラメータ値がvalより小さい場合

メソッド BSLt( bmdest As%String 、 vbs As%String 、 val As%Integer )

{

tmpLt = .. GetNewTMP ()を 設定し ます

do .. BSLtAbs ( bmdest 、 vbs 、 val )、.. BSSign ( tmpLt 、 vbs 、-1)

if val '<0 do .. BMOr ( bmdest 、 tmpLt ) if 1

ELSE do .. BMNot ( bmdest )、.. BMAnd ( bmdest 、 tmpLt )、.. BSNe ( tmpLt 、 vbs 、 val )、.. BMAnd ( bmdest 、 tmpLt )

kill @ tmpLt quit

}



/// bmdestビット配列にvbsビットスライスインデックスからのサンプルを配置し、

///パラメータ値がval1以上val2以下

メソッド BSGeLe( bmdest As%String 、 vbs As%String 、 val1 As%Integer 、 val2 As%Integer )

{

tmpGeLe = .. GetNewTMP ()を 設定し ます

do .. BSGe ( bmdest 、 vbs 、 val1 )、.. BSLe ( tmpGeLe 、 vbs 、 val2 )、.. BMAnd ( bmdest 、 tmpGeLe )

kill @ tmpGeLe quit

}



/// vbsビットスライスインデックスから選択範囲をbmdestビットマップに配置し、

///パラメータ値がval1以上val2より小さい場合

メソッド BSGeLt( bmdest As%String 、 vbs As%String 、 val1 As%Integer 、 val2 As%Integer )

{

tmpGeLt = .. GetNewTMP ()を 設定し ます

do .. BSGe ( bmdest 、 vbs 、 val1 )、.. BSLt ( tmpGeLt 、 vbs 、 val2 )、.. BMAnd ( bmdest 、 tmpGeLt )

kill @ tmpGeLt quit

}



/// bmdestビット配列にvbsビットスライスインデックスからのサンプルを配置し、

///パラメータ値がval1より大きく、val2以下

メソッド BSGtLe( bmdest As%String 、 vbs As%String 、 val1 As%Integer 、 val2 As%Integer )

{

tmpGtLe = .. GetNewTMP ()を 設定し ます

do .. BSGt ( bmdest 、 vbs 、 val1 )、.. BSLe ( tmpGtLe 、 vbs 、 val2 )、.. BMAnd ( bmdest 、 tmpGtLe )

kill @ tmpGtLe quit

}



/// vbsビットスライスインデックスから選択範囲をbmdestビットマップに配置し、

///パラメータ値がval1より大きく、val2より小さい場合

メソッド BSGtLt( bmdest As%String 、 vbs As%String 、 val1 As%Integer 、 val2 As%Integer )

{

tmpGtLt = .. GetNewTMP ()を 設定し ます

do .. BSGt ( bmdest 、 vbs 、 val1 )、.. BSLt ( tmpGtLt 、 vbs 、 val2 )、.. BMAnd ( bmdest 、 tmpGtLt )

kill @ tmpGtLt quit

}



/// vbsビットスライスインデックスから選択範囲をbmdestビットマップに配置し、

///絶対値のパラメーター値がvalより小さい場合

メソッド BSLtAbs( bmdest As%String 、 vbs As%String 、 val As%Integer )

{

set bswork = .. GetNewTMP ()、 test = .. GetNewTMP ()

kill @ bmdest set vbit = .. CvtToBin ( val )、 ixmax = $ order (@ vbs @( "" )、-1)

kill @ test merge @ test = @(.. BMGLOB )@( "EXIST" )

if ixmax < $ length ( vbit ) {

merge @ bmdest = @ test

} else {

ix = ixmaxの場合 :-1:2 {

kill @ bswork merge @ bswork = @ vbs @( ix )

.. BMNot ( bswork )、.. BMAnd ( bswork 、 test )

do : $ extract ( vbit 、 ix ).. BMOr ( bmdest 、 bswork )、.. BMNot ( bswork )

.. BMAnd ( テスト 、 bswork )

}

}

@testを強制 終了 、@ bsworkを 終了

}



/// beatleysインデックスのグループ化関数

///最大値を返します(オプションのパラメーター付き

/// bsmin '= 0-minimum)vbsビットスライスインデックスからビットマップを選択するため

メソッド BSMax( vbs As%String 、 ビットマップ As%String 、 bsmin As%String ) As%Integer

{

set bsmin = '' $ get ( bsmin )、 bswork = .. GetNewTMP ()

resBSM = .. GetNewTMP ()、 tmpBSM = .. GetNewTMP ()を設定します

merge @ resBSM = @ vbs @(1) do : ' bsmin .. BMNot ( resBSM ) do .. BMAnd ( resBSM 、 ビットマップ )

if .. BMCount ( resBSM ) set min = 0

ELSE set min = 1 kill @ resBSM merge @ resBSM = @ vbs @(1) do : bsmin .. BMNot ( resBSM ) do .. BMAnd ( resBSM 、 ビットマップ )

for ix = $ order (@ vbs @( "" )、-1):-1:2 {

@ tmpBSMを強制終了 、@ bsworkを マージ @ tmpBSM = @ resBSM 、@ bswork = @ vbs @( ix )

do : min .. BMNot ( bswork ) do .. BMAnd ( tmpBSM 、 bswork )

if .. BMCount ( tmpBSM ) kill @ resBSM merge @ resBSM = @ tmpBSM

}

set pos = .. BMOrder ( resBSM 、0) quit : ' pos 0

set val = .. CvtFromSlice (.. GetSlice ( vbs 、 pos ))

kill @ bswork 、@ resBSM 、@ tmpBSM quit val

}



メソッド BSMin( vbs As%String 、 ビットマップ As%String ) As%Integer

{

quit .. BSMax ( vbs 、 bitmap 、1)

}



/// vbsビットスライスインデックスからビットマップサンプルの値の合計を返します

メソッド BSSum( vbs As%String 、 ビットマップ As%String ) As%Integer

{

セット bswork = .. GetNewTMP ()、 resBSSum = .. GetNewTMP ()、 tmpBSSum = .. GetNewTMP ()

merge @ resBSSum = @ vbs @(1) do .. BMNot ( resBSSum )、.. BMAnd ( resBSSum 、 bitmap ) set slice = ""

ix = 2:1: $ order (@ vbs @( "" )、-1) kill @ tmpBSSum merge @ tmpBSSum = @ vbs @( ix ) do .. BMAnd ( tmpBSSum 、 resBSSum ) set $ list ( slice 、 ix )= .. BMCount ( tmpBSSum )

set val = .. CvtFromSlice ( スライス )

kill @ resBSSum merge @ resBSSum = @ vbs @(1) do .. BMAnd ( resBSSum 、 bitmap ) set slice = ""

ix = 2:1: $ order (@ vbs @( "" )、-1) kill @ tmpBSSum merge @ tmpBSSum = @ vbs @( ix ) do .. BMAnd ( tmpBSSum 、 resBSSum ) set $ list ( slice 、 ix )= .. BMCount ( tmpBSSum )

set val = val- .. CvtFromSlice ( スライス )

kill @ bswork 、@ resBSSum 、@ tmpBSSum quit val

}



///ビットマップとビットスライスインデックスを埋めるためのメソッド

///

///ビットマップインデックスの対応するビットを設定します

///このプロパティの指定された値

///オプションパラメータsetexist = 1を使用して、ビットを

///既存のレコードのビットマップインデックス(正しいために必要

/// BMNot())メソッドの操作

メソッド SetBitMap( idfact As%Integer 、 プロパティ As%String 、 値 As%String 、 setexist As%String )

{

set idf0 = idfact -1 \ .. # MAXBITLENGTH 、 idf1 = idfact -1#.. #MAXBITLENGTH +1

set : $ get ( setexist ) $ bit (@(.. BMGLOB )@( "EXIST" 、 idf0 )、 idf1 )= 1

set $ bit (@(.. BMGLOB )@( "I" 、 property 、 value 、 idf0 )、 idf1 )= 1

やめる

}



/// beatleysインデックスの対応するビットを設定します

///このプロパティの指定された値。

///オプションパラメータsetexist-SetBitMap()に類似

メソッド SetBitSlice( idfact As%Integer 、 プロパティ As%String 、 値 As%Integer 、 setexist As%String )

{

set idf0 = idfact -1 \ .. # MAXBITLENGTH 、 idf1 = idfact -1#.. #MAXBITLENGTH +1

set : $ get ( setexist ) $ bit (@(.. BMGLOB )@( "EXIST" 、 idf0 )、 idf1 )= 1

set v = .. CvtToBin (+ value )

ix = 1:1: $ length ( v ) set : $ extract ( v 、 ix ) $ bit (@(.. BMGLOB )@( "S" 、 property 、 ix 、 idf0 )、 idf1 )= 1

やめる

}



///を含むインデックスグローバルのサブノードの名前を返します

///ビットマップインデックス(スライス= 0または未定義の場合)またはビットスライス(ghbスライス '= 0)

///このプロパティ。 プロパティが空または定義されていない場合-

///その後、既存のレコードのビットマップインデックス

メソッド GetBitMapName( プロパティ As%String 、 スライス As%String ) As%String

{

quit : $ get ( property )= "" $ name (@(.. BMGLOB )@( "EXIST" ))

quit $ name (@(.. BMGLOB )@( $ select (+ $ get ( slice ): "S" 、1: "I" )、 property ))

}



///デモの充填と選択

///

ClassMethod Populate( Count As%String = 10000 )

{

set ix = .. %New ()

ixを 設定し ます。 BMGLOB = $ name (^ BMI)

set count = $ get ( count 、10000)、 m = 0

セット 名 = $ listbuild ( "SantaClause" 、 "Crocodile" 、 "Simba" )

色の 設定 = $ listbuild ( "シアン" 、 "マゼンタ" 、 "イエロー" 、 "ブラック" )

if $ sortbegin (^ BMI)

idfact = 1の場合:1: カウント {

set name = $ list ( names 、1 + $ random ( $ listlength ( names ))))

set color = $ list ( colors 、1 + $ random ( $ listlength ( colors ))))

設定 長 = 10 + $ランダム (90)

重みの 設定 =(10+ $ランダム (40))* 100

; 色のビットマップインデックスを作成します

ixを行い ます。 SetBitMap ( idfact 、 "C" 、 color 、1)

; 重量と長さに​​ついては、ビートリーインデックスを作成します

ixを行い ます。 SetBitSlice ( idfact 、 "L" 、 length )

ixを行い ます。 SetBitSlice ( idfact 、 "W" 、 weight )

; テストサンプル(以下を参照)をテストするために、

; 黒と黄色のワニの総重量45〜70 cm

; 包括的に

set :(( color = "Black" )!( color = "Yellow" ))&( 長さ '<45)&( 長さ '> 70) m = m + 重量

}

if $ sortend (^ BMI)

m _ "gramms total"と 書いてください !

IX を 殺す

}



///テストサンプル

ClassMethod TestGetData()

{

set ix = .. %New ()

ixを 設定し ます。 BMGLOB = $ name (^ BMI)

b = .. GetNewTMP ()、 b1 = .. GetNewTMP ()を設定します

ixを行い ます。 BMEq ( b 、 ix。GetBitMapName ( "C" )、 "Black" )

ixを行い ます。 BMEq ( b1 、 ix。GetBitMapName ( "C" )、 "Yellow" )

ixを行い ます。 BMOr ( b 、 b1 )

ixを行い ます。 BSGeLe ( b1 、 ix。GetBitMapName ( "L" 、1)、45.70)

ixを行い ます。 BMAnd ( b 、 b1 )

カウント = ixに 設定し ます 。 BMCount ( b )

書き込み 数 _ 「選択されたアイテム」、!

; 選択したものの総重量を決定する

ixを 書き ます。 BSSum ( ix。GetBitMapName ( "W" 、1)、 b )_ "gramms total" ,!

do .. KillAllTMP ()

IX を 殺す

}



}


添付コードには、ビットマップインデックスとクラスおよびルーチンのビットスライスを使用してデータウェアハウスを開発するための完全な関数セットが含まれており、これらの構造で必要なすべての操作をサポートします。 また、テストストレージにデータを入力するためのデモメソッドも含まれています。この方法では、グループ化関数の値(合計)が後続のテスト要求に対して直接計算されます。



##クラス ( User.BitMapSlice )を実行します。 人口 (1,000,000) ; 万件の記録



このテスト要求を実行するためのメソッド。同じグループ化関数の値がビットスライスを使用して計算されます。



##クラス ( User.BitMapSlice )を実行します。 TestGetData ()



結果とそれに費やした時間を比較できます。



短縮されたCOS構文に慣れている人のために、Cachéスタジオバージョン5.2以降では、選択したコードフラグメントを完全な形式から短い形式に簡単に変換できることを思い出してください-Ctrl-Shift-Eまたはその逆-Ctrl-E

結論として、1つの微妙な点についてコメントする必要があります。 ^ CacheTempまたは^ mtempプレフィックスを使用してグローバルでフェッチするために、中間および結果のビットマップインデックスを構築することをお勧めします。 このようなグローバルはCACHETEMPデータベースに物理的に配置されており、ログに記録されないため、必要がないため、 ローカル変数を使用するよりも作業が効率的です。 この目的でローカル変数を使用することも、別の理由で望ましくありません。ユーザープロセスの16メガバイトのメモリ制限に達する可能性があります。

イタリック体の強調は、CachéDBMSの新しいバージョンには適用されません。
  1. 大規模なローカル配列
  2. 拡張メモリ
  3. 無制限のローカル配列
この記事で説明するコードは、DeepSee製品のプレゼンテーションの1つでインターシステムズから提供された情報に基づいており、その後、MacovaSoftのOrtofactデータウェアハウスで使用されました。



All Articles