воскресенье, 29 мая 2016 г.

MUMPS: Операции с древовидными индексами

К операциям с древовидными индексами относятся операции, использующие деревья с индексами и реализующие над ними теоретико - множественные операции. К таким операциям относят логические операции над множествами: OR (ИЛИ), AND (И), и другие. При этом деревья используются для хранения множеств - операндов и результата операции.

Структурно древовидный индекс удерживает как значения атрибутов, так и идентификаторы записей. Поэтому в операциях над индексными деревьями есть две группы операций - как над деревьями значений атрибутов, так и над деревьями, включающими идентификаторы записей.

Для простоты будем оперировать разработанным ранее примером поддержки простых индексов:
CreateRecords()
 k ^Index
 k ^Data
 n i,Figures,Colors,Counts,Figure,Color,Count,id
 s Figures="квадрат~круг~отрезок~треугольник"
 s Colors="красный~зелёный~синий~белый"
 s Counts="2~5~12~8"
 f i=1:1:12 d
 . s Figure=$p(Figures,"~",$r(4)+1)
 . s Color=$p(Colors,"~",$r(4)+1)
 . s Count=$p(Counts,"~",$r(4)+1)
 . s id=$$InsertRecord(Figure_"~"_Color_"~"_Count)
 q
InsertRecord(RecordValues)
 n id s id=$i(^Data)
 l +^Data(id)
 s ^Data(id)=RecordValues
 d InsertIndexRecords(id,RecordValues)
 l -^Data(id)
 q id
DeleteRecord(id)
 q:'$d(^Data(id))
 l +^Data(id)
 n RecordValues s RecordValues=$g(^Data(id))
 d DeleteIndexRecords(id,RecordValues)
 k ^Data(id)
 l -^Data(id)
 q
UpdateRecord(id,RecordValues)
 q:'$d(^Data(id))
 l +^Data(id)
 n OldRecordValues s OldRecordValues=$g(^Data(id))
 d DeleteIndexRecords(id,OldRecordValues)
 s ^Data(id)=RecordValues
 d InsertIndexRecords(id,RecordValues)
 l -^Data(id)
 q
InsertIndexRecords(id,RecordValues)
 d InsertIndexRecord("Figure",id,$p((RecordValues),"~",1))
 d InsertIndexRecord("Color",id,$p((RecordValues),"~",2))
 q
DeleteIndexRecords(id,RecordValues)
 d DeleteIndexRecord("Figure",id,$p((RecordValues),"~",1))
 d DeleteIndexRecord("Color",id,$p((RecordValues),"~",2))
 q
InsertIndexRecord(IndexName,id,Value)
 s ^Index(IndexName,Value,id)=""
 q
DeleteIndexRecord(IndexName,id,Value)
 k ^Index(IndexName,Value,id)
 q
Рассмотрим операции над деревьями значений атрибутов. К ним можно отнести операции выборки поддерева с заданным значением атрибута, выбрать поддерево со значениями атрибута меньшими чем заданное, со значениями большими чем заданное, со значениями между двумя заданными, вычесть поддерево из другого поддерева, и получить число различных значений атрибутов. Приведем примерные реализации этих операций и как их использовать в контрольном примере.

Выборка поддерева с заданным значением атрибута.
EQ(ret,name)
 m @ret=@name
 q ret
USER>d EQ^TREEOP($NA(a),$na(^Index("Figure","круг")))
Получить поддерево из заданного поддерева кроме указанного значения.
NE(ret,name,value)
 m @ret=@name
 k @root@(value)
 q
NE2(ret,name,value...)
 m @ret=@name
 n i f i=1:1:value k:$d(value(i)) @ret@(value(i))
 q

USER>d NE^TREEOP($na(res), » 
   $na(^Index("Figure")),"круг")
USER>d NE2^TREEOP($na(res), »
   $na(^Index("Figure")),"круг","квадрат")
Получили всё поддерево с индексом кроме поддерева с указанным значением. В первом случае стандартный М код, с вычитанием одного значения, во втором - с расширением COS, с вычитанием значений, заданных списком.

Выборка поддерева со значениями атрибута, меньшими заданного.
LT(ret,name,value)
 n i
 s i=value f  s i=$o(@name@(i),-1) q:i=""  m @ret@(i)=@name@(i)
 q
USER>d LT^TREEOP($na(r),$na(^Index("Figure")),"отрезок")
Выборка поддерева со значениями атрибутов, большими чем заданное.
GT(ret,name,value)
 n i
 s i=value f  s i=$o(@name@(i)) q:i=""  m @ret@(i)=@name@(i)
 q
USER>k  d GT^TREEOP($na(r),$na(^Index("Figure")),"отрезок")
Выборка поддерева со значениями между двумя заданными.
BT(ret,name,begin,end)
 n i
 s i=begin f  s i=$o(@name@(i)) q:(i="")!(i]]end)!(i=end)  d
 . m @ret@(i)=@name@(i)
 q
    USER>d BT^TREEOP($na(r),$na(^Index("Figure")), »
    "квадрат","треугольник")
Получить число различных значений атрибутов.
COUNT(name)
 n ret,id s ret=0
 s id="" f  s id=$o(@name@(id)) q:id=""  s ret=ret+1
 q ret
USER>w $$COUNT^TREEOP($na(^Index("Figure","треугольник")))
Рассмотрим операции с поддеревьями идентификаторов. К ним можно отнести трансформирование дерева - списка значений + списки идентификаторов в дерево списка идентификаторов, операцию объединения множеств (OR), операцию пересечения множеств (AND) и операцию дополнения множеств (SUB).

Сократить дерево на один уровень, или трансформировать дерево - список значений + список идентификаторов в дерево - список идентификаторов:
SIMPLE(ret,name)
 n i
 s i="" f  s i=$o(@name@(i)) q:i=""  m @ret=@name@(i)
 q
Получить идентификаторы, содержащиеся в индексе по полю Figure:
USER>d SIMPLE^TREEOP($na(r),$na(^Index("Figure")))
Получить идентификаторы, у которых значение Figure лежит между заданными значениями:
USER>d BT^TREEOP($na(r2), »
  $na(^Index("Figure")),"квадрат","треугольник")
USER>d SIMPLE^TREEOP($na(r),$na(r2))
Получить объединение множеств:
OR(ret,names...)
 n i
 f i=1:1:names m:$d(names(i)) @ret=@(names(i))
 q
Используя эту операцию, получить идентификаторы записей, у которых значение Figure равно "круг" или "отрезок":
d OR^TREEOP($na(r),$na(^Index("Figure","круг")), »
     $na(^Index("Figure","отрезок")))
Найти пересечение множеств:
AND(ret,names...)
 n id,i,j,k,place
 s id="" f  s i=1 s id=$$ANDnext() q:id=""  s @ret@(id)=""
 q
ANDnext()
ANDrep
 s id=$o(@names(i)@(id))
 q:id="" ""
 f j=i+1:1:i+names-1 s place=((j-1)#names)+1 »
    i '$d(@names(place)@(id)) s i=place g ANDrep
 q id
Используя операцию пересечения найти красные круги:
    d AND^TREEOP($na(r),$na(^Index("Figure","круг")), »
    $na(^Index("Color","красный")))
Найти дополнение множеств:
SUB(ret,from,what...)
 n i,id
 m @ret=@from
 f i=1:1:what d:$d(what(i))
 . s id="" f  s id=$o(@what(i)@(id)) q:id=""  k @ret@(id)
 q
Используя операцию дополнения, найти круги и не красные:
d SUB^TREEOP($na(r),$na(^Index("Figure","круг")), »
    $na(^Index("Color","красный")))
Кроме приведенных операций в практике также встречаются другие, такие как взять первое или последнее значение, или взять начиная с n-го m значений. Для них также можно составить обобщенные операции, использующие косвенность аргумента.

Несложно видеть, что собственно сами операции на индексных структурах просты, если их описывать обобщенно, в косвенной форме, и сложность использования индексов проявляется тогда, когда их жестко прописывают в коде программ, используя предопределенные магические константы.

Подробнее о книге "MUMPS СУБД"

Комментариев нет:

Отправить комментарий