Собственные типы индексов в СУБД caché
TRANSCRIPT
Собственные типы индексов (они же функциональные индексы)
Конечный результат
Property A As %String;
Property B As %String;
Index someind On (A,B) As CustomPackage.CustomIndex;
Собственно квадродерево
Class SpatialIndex.Indexer {
Method %OnNew(indexGlobal As %String) As %Status
Method Insert(x As %Float, y As %Float, id As %String)
Method Delete(x As %Float, y As %Float, id As %String)
}
ClassMethod InsertIndex(pID, pArg... As %Binary) [ CodeMode = generator] {
if %mode'="method" {
set IndexGlobal = ..IndexLocation(%class,%property)
$$$GENERATE($C(9)_"set indexer = " _
"##class(SpatialIndex.Indexer).%New($Name("_IndexGlobal_"))")
$$$GENERATE($C(9)_"do indexer.Insert(pArg(1),pArg(2),pID)")
}
}
Class SpatialIndex.Index Extends %Library.FunctionalIndex
Пример использования
Class SpatialIndex.Test Extends %Persistent {
Property Name As %String(MAXLEN = 300);
Property Latitude As %String;
Property Longitude As %String;
Index coord On (Latitude, Longitude) As SpatialIndex.Index;
}
SpatialIndex.Test.1.INT
zcoordInsertIndex(pID,pArg...) public {
set indexer =
##class(SpatialIndex.Indexer).%New($Name(^SpatialIndex.TestI("coord")))
do indexer.Insert(pArg(1),pArg(2),pID)
}
zcoordUpdateIndex(pID,pArg...) public {
set indexer =
##class(SpatialIndex.Indexer).%New($Name(^SpatialIndex.TestI("coord")))
do indexer.Delete(pArg(3),pArg(4),pID)
do indexer.Insert(pArg(1),pArg(2),pID)
}
SpatialIndex.Test.1.INT
%SaveData(id) {
if insert {
// ...
do ..coordInsertIndex(id,i%Latitude,i%Longitude,"")
// ...
} else {
// ...
do ..coordUpdateIndex(id,i%Latitude,i%Longitude,zzc27v3,zzc27v2,"")
// ...
}
}
Так данные индекса выглядят в глобале
USER>zwrite ^SpatialIndex.TestI("coord")
^SpatialIndex.TestI("coord"," ")=$lb(-180,-90,180.0001,90.0001,0,0)
...
^SpatialIndex.TestI("coord"," 30")=$lb(.00005,.00005,90.000075,45.000075,0,0)
^SpatialIndex.TestI("coord"," 300")=$lb(.00005,.00005,45.0000625,22.5000625,1,0)
^SpatialIndex.TestI("coord"," 301")=$lb(45.0000625,.00005,90.000075,22.5000625,0,0)
^SpatialIndex.TestI("coord"," 3010")=$lb(45.0000625,.00005,67.50006875,11.25005625,1,0)
^SpatialIndex.TestI("coord"," 3011")=$lb(67.50006875,.00005,90.000075,11.25005625,1,0)
^SpatialIndex.TestI("coord"," 3012")=$lb(45.0000625,11.25005625,67.50006875,22.5000625,0,0)
^SpatialIndex.TestI("coord"," 30120")=$lb(45.0000625,11.25005625,56.250065625,16.875059375,1,0)
...
А как же запросы?
SELECT *
FROM SpatialIndex.Test
WHERE %ID %FIND search_index(coord, 'window',
'minx=56,miny=56,maxx=57,maxy=57')
Снова SpatialIndex.Indexer
ClassMethod Find(queryType As %Binary, queryParams As %String) As
%Library.Binary [ CodeMode = generator, SqlProc ]
{
if %mode'="method" {
set IndexGlobal = ..IndexLocation(%class,%property)
$$$GENERATE($C(9)_"set result = ##class(SpatialIndex.SQLResult).%New()")
$$$GENERATE($C(9)_"do result.PrepareFind($Name("_IndexGlobal_"),
queryType, queryParams)")
$$$GENERATE($C(9)_"quit result")
}
}
search_index(coord, 'window', 'minx=56,miny=56,maxx=57,maxy=57')
Метод, сгенерированный в SpatialIndex.Test.1.INT
zcoordFind(queryType,queryParams) public { Set:'$isobject($get(%sqlcontext)) %sqlcontext=##class(%Library.ProcedureContext).%New()
set result = ##class(SpatialIndex.SQLResult).%New()
do result.PrepareFind($Name(^SpatialIndex.TestI("coord")), queryType,
queryParams)
quit result }
search_index(coord, 'window', 'minx=56,miny=56,maxx=57,maxy=57')
Class SpatialIndex.SQLResult Extends %SQL.AbstractFind
Property ResultBits [ MultiDimensional, Private ];
Method PrepareFind(indexGlobal As %String, queryType As %String, queryParams As %Binary) As %Status { // … }
Method NextChunk(ByRef pChunk As %Integer = "") As %Binary { set pChunk = $order(i%ResultBits(pChunk),1,tBits) quit:pChunk="" "" quit tBits }
Method ContainsItem(pItem As %String) As %Boolean { set tChunk = (pItem\64000)+1, tPos=(pItem#64000)+1 quit $bit($get(i%ResultBits(tChunk)),tPos) }
В итоге запросы выглядят так:
SELECT *
FROM SpatialIndex.Test
WHERE %ID %FIND search_index(coord,'radius','x=55,y=55,radiusX=2,radiusY=2') and name %StartsWith 'Z'
Параметр size предиката %FIND
SELECT *
FROM SpatialIndex.Test
WHERE name %startswith 'za'
and %ID %FIND
search_index(coord,'radius','x=55,y=55,radius=2')
size ((10))
Спасибо. Вопросы?
http://habrahabr.ru/company/intersystems/blog/272689/