Files
secondo/Algebras/MTree/MTreeAlgebra.cpp
2026-01-23 17:03:45 +08:00

1440 lines
40 KiB
C++

/*
\newpage
----
This file is part of SECONDO.
Copyright (C) 2004, University in Hagen, Department of Computer Science,
Database Systems for New Applications.
SECONDO is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SECONDO is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
//[_] [\_]
//characters [1] verbatim: [$] [$]
//characters [2] formula: [$] [$]
//characters [3] capital: [\textsc{] [}]
//characters [4] teletype: [\texttt{] [}]
1 Implementation file "MTreeAlgebra.cpp"[4]
January-May 2008, Mirko Dibbert
1.1 Overview
This file contains the implementation of the mtree algebra.
1.1 Includes and defines
*/
#include "Algebra.h"
#include "NestedList.h"
#include "QueryProcessor.h"
#include "Algebras/Relation-C++/RelationAlgebra.h"
#include "Algebras/TupleIdentifier/TupleIdentifier.h"
#include "MTreeAlgebra.h"
#include "MTree.h"
#include "ListUtils.h"
#include "Symbols.h"
extern NestedList *nl;
extern QueryProcessor *qp;
extern AlgebraManager *am;
using namespace std;
using namespace gtree;
using namespace gta;
namespace mtreeAlgebra {
/********************************************************************
1.1 Type constructor ~mtree~
********************************************************************/
static ListExpr MTreeProp()
{
ListExpr examplelist = nl->TextAtom();
nl->AppendText(examplelist, "<relation> createmtree [<attrname>]"
" where <attrname> is the key");
return (nl->TwoElemList(
nl->TwoElemList(nl->StringAtom("Creation"),
nl->StringAtom("Example Creation")),
nl->TwoElemList(examplelist,
nl->StringAtom("(let mymtree = pictures "
"createmtree[pic] "))));
}
ListExpr OutMTree(ListExpr type_Info, Word w)
{
#ifdef __MTREE_OUTFUN_PRINT_STATISTICS
static_cast<MTree*>(w.addr)->printTreeInfos();
#endif
return nl->TheEmptyList();
}
Word InMTree(
ListExpr type_Info, ListExpr value,
int errorPos, ListExpr &error_Info, bool &correct)
{
correct = false;
return SetWord(Address(0));
}
Word Createmtree(const ListExpr type_Info)
{ return SetWord(new MTree()); }
void DeleteMTree(const ListExpr type_Info, Word &w)
{
static_cast<MTree*>(w.addr)->deleteFile();
delete static_cast<MTree*>(w.addr);
w.addr = 0;
}
bool OpenMTree(SmiRecord &valueRecord, size_t &offset,
const ListExpr type_Info, Word &w)
{
SmiFileId fileid;
valueRecord.Read(&fileid, sizeof(SmiFileId), offset);
offset += sizeof(SmiFileId);
MTree *mtree = new MTree(fileid);
w = SetWord(mtree);
return true;
}
bool SaveMTree(SmiRecord &valueRecord, size_t &offset,
const ListExpr type_Info, Word &w)
{
SmiFileId fileId;
MTree *mtree = static_cast<MTree*>(w.addr);
fileId = mtree->fileId();
if (fileId)
{
valueRecord.Write(&fileId, sizeof(SmiFileId), offset);
offset += sizeof(SmiFileId);
return true;
}
else
{
return false;
}
}
void CloseMTree(const ListExpr type_Info, Word &w)
{
MTree *mtree = (MTree*)w.addr;
delete mtree;
}
Word CloneMTree(const ListExpr type_Info, const Word &w)
{ return SetWord(Address(0)); }
int SizeOfMTree()
{ return sizeof(MTree); }
bool CheckMTree(ListExpr typeName, ListExpr &error_Info)
{ return nl->IsEqual(typeName, MTree::BasicType()); }
TypeConstructor
mtreeTC(MTree::BasicType(), MTreeProp,
OutMTree, InMTree,
0, 0,
Createmtree, DeleteMTree,
OpenMTree, SaveMTree,
CloseMTree, CloneMTree,
0,
SizeOfMTree,
CheckMTree);
/********************************************************************
1.1 Operators
1.1.1 Value mappings
1.1.1.1 createmtreeRel[_]VM
This value mapping function is used for all "createmtree"[4] operators, which expect a relation and non-distdata attributes.
It is designed as template function, which expects the count of arguments as template paremeter.
********************************************************************/
template<unsigned paramCnt> int
createmtreeRel_VM(Word *args, Word &result, int message,
Word &local, Supplier s)
{
result = qp->ResultStorage(s);
MTree *mtree =
static_cast<MTree*>(result.addr);
Relation *relation =
static_cast<Relation*>(args[0].addr);
int attrIndex =
static_cast<CcInt*>(args[paramCnt].addr)->GetIntval();
string typeName =
static_cast<CcString*>(args[paramCnt+1].addr)->GetValue();
string distfunName =
static_cast<CcString*>(args[paramCnt+2].addr)->GetValue();
string dataName =
static_cast<CcString*>(args[paramCnt+3].addr)->GetValue();
string configName =
static_cast<CcString*>(args[paramCnt+4].addr)->GetValue();
DistDataId id = DistDataReg::getId(typeName, dataName);
mtree->initialize(id, distfunName, configName);
Tuple *tuple;
GenericRelationIterator *iter = relation->MakeScan();
while ((tuple = iter->GetNextTuple()) != 0)
{
Attribute *attr = tuple->GetAttribute(attrIndex);
if(attr->IsDefined())
{
mtree->insert(attr, tuple->GetTupleId());
}
tuple->DeleteIfAllowed();
}
delete iter;
#ifdef __MTREE_PRINT_INSERT_INFO
cout << endl;
#endif
return 0;
}
/********************************************************************
1.1.1.1 createmtreeStream[_]VM
This value mapping function is used for all "createmtree"[4] operators, which expect a tupel stream and non-distdata attributes.
It is designed as template function, which expects the count of arguments as template paremeter.
********************************************************************/
template<unsigned paramCnt>
int createmtreeStream_VM(
Word *args, Word &result, int message,
Word &local, Supplier s)
{
result = qp->ResultStorage(s);
MTree *mtree = static_cast<MTree*>(result.addr);
void *stream =
static_cast<Relation*>(args[0].addr);
int attrIndex =
static_cast<CcInt*>(args[paramCnt].addr)->GetIntval();
string typeName =
static_cast<CcString*>(args[paramCnt+1].addr)->GetValue();
string distfunName =
static_cast<CcString*>(args[paramCnt+2].addr)->GetValue();
string dataName =
static_cast<CcString*>(args[paramCnt+3].addr)->GetValue();
string configName =
static_cast<CcString*>(args[paramCnt+4].addr)->GetValue();
DistDataId id = DistDataReg::getId(typeName, dataName);
mtree->initialize(id, distfunName, configName);
Word wTuple;
qp->Open(stream);
qp->Request(stream, wTuple);
while (qp->Received(stream))
{
Tuple *tuple = static_cast<Tuple*>(wTuple.addr);
Attribute *attr = tuple->GetAttribute(attrIndex);
if(attr->IsDefined())
{
mtree->insert(attr, tuple->GetTupleId());
}
tuple->DeleteIfAllowed();
qp->Request(stream, wTuple);
}
qp->Close(stream);
#ifdef __MTREE_PRINT_INSERT_INFO
cout << endl;
#endif
return 0;
}
/********************************************************************
1.1.1.1 createmtreeDDRel[_]VM
This value mapping function is used for all "createmtree"[4] operators, which expect a relation and distdata attributes.
It is designed as template function, which expects the count of arguments as template paremeter.
********************************************************************/
template<unsigned paramCnt>
int createmtreeDDRel_VM(
Word *args, Word &result, int message,
Word &local, Supplier s)
{
result = qp->ResultStorage(s);
MTree *mtree = static_cast<MTree*>(result.addr);
Relation *relation =
static_cast<Relation*>(args[0].addr);
int attrIndex =
static_cast<CcInt*>(args[paramCnt].addr)->GetIntval();
string distfunName =
static_cast<CcString*>(args[paramCnt+1].addr)->GetValue();
string configName =
static_cast<CcString*>(args[paramCnt+2].addr)->GetValue();
Tuple *tuple;
GenericRelationIterator *iter = relation->MakeScan();
DistDataId id;
while ((tuple = iter->GetNextTuple()))
{
DistDataAttribute *attr = static_cast<DistDataAttribute*>(
tuple->GetAttribute(attrIndex));
if(attr->IsDefined())
{
if (mtree->isInitialized())
{
if(attr->distdataId() != id)
{
const string seperator =
"\n" + string(70, '-') + "\n";
cmsg.error()
<< seperator
<< "Operator createmtree: " << endl
<< "Got distdata attributes of different "
<< "types!" << endl << "(type constructor "
<< "or distdata type are not equal)"
<< seperator << endl;
cmsg.send();
tuple->DeleteIfAllowed();
delete iter;
return CANCEL;
}
}
else
{ // initialize mtree
id = attr->distdataId();
DistDataInfo info = DistDataReg::getInfo(id);
string dataName = info.name();
string typeName = info.typeName();
if (distfunName == DFUN_DEFAULT)
{
distfunName = DistfunReg::defaultName(typeName);
}
// check if distance function is defined
if (!DistfunReg::isDefined(distfunName, id))
{
const string seperator =
"\n" + string(70, '-') + "\n";
cmsg.error()
<< seperator
<< "Operator createmtree: " << endl
<< "Distance function \"" << distfunName
<< "\" for type \"" << typeName
<< "\" is not defined!" << endl
<< "Defined distance functions: " << endl
<< endl
<< DistfunReg::definedNames(typeName)
<< seperator << endl;
cmsg.send();
tuple->DeleteIfAllowed();
delete iter;
return CANCEL;
}
if (!DistfunReg::getInfo(
distfunName, typeName, dataName).isMetric())
{
const string seperator =
"\n" + string(70, '-') + "\n";
cmsg.error()
<< seperator
<< "Operator createmtree: " << endl
<< "Distance function \"" << distfunName
<< "\" with \"" << dataName
<< "\" data for type" << endl
<< "\"" << typeName << "\" is no metric!"
<< seperator << endl;
cmsg.send();
tuple->DeleteIfAllowed();
delete iter;
return CANCEL;
}
mtree->initialize(
attr->distdataId(), distfunName, configName);
}
// insert attribute into mtree
char* tdata = attr->getData();
DistData *data = new DistData(attr->size(), tdata);
delete[] tdata;
mtree->insert(data, tuple->GetTupleId());
}
tuple->DeleteIfAllowed();
}
delete iter;
#ifdef __MTREE_PRINT_INSERT_INFO
cout << endl;
#endif
return 0;
}
/********************************************************************
1.1.1.1 createmtreeDDStream[_]VM
This value mapping function is used for all "createmtree"[4] operators, which expect a tupel stream and distdata attributes.
It is designed as template function, which expects the count of arguments as template paremeter.
********************************************************************/
template<unsigned paramCnt>
int createmtreeDDStream_VM(
Word *args, Word &result, int message,
Word &local, Supplier s)
{
result = qp->ResultStorage(s);
MTree *mtree = static_cast<MTree*>(result.addr);
void *stream =
static_cast<Relation*>(args[0].addr);
int attrIndex =
static_cast<CcInt*>(args[paramCnt].addr)->GetIntval();
string distfunName =
static_cast<CcString*>(args[paramCnt+1].addr)->GetValue();
string configName =
static_cast<CcString*>(args[paramCnt+2].addr)->GetValue();
DistDataId id;
Word wTuple;
qp->Open(stream);
qp->Request(stream, wTuple);
while (qp->Received(stream))
{
Tuple *tuple = static_cast<Tuple*>(wTuple.addr);
DistDataAttribute *attr = static_cast<DistDataAttribute*>(
tuple->GetAttribute(attrIndex));
if(attr->IsDefined())
{
if (mtree->isInitialized())
{
if(attr->distdataId() != id)
{
const string seperator =
"\n" + string(70, '-') + "\n";
cmsg.error()
<< seperator
<< "Operator createmtree: " << endl
<< "Got distdata attributes of different "
<< "types!" << endl << "(type constructor "
<< "or distdata type are not equal)"
<< seperator << endl;
cmsg.send();
tuple->DeleteIfAllowed();
return CANCEL;
}
}
else
{ // initialize mtree
id = attr->distdataId();
DistDataInfo info = DistDataReg::getInfo(id);
string dataName = info.name();
string typeName = info.typeName();
if (distfunName == DFUN_DEFAULT)
{
distfunName = DistfunReg::defaultName(typeName);
}
// check if distance function is defined
if (!DistfunReg::isDefined(distfunName, id))
{
const string seperator =
"\n" + string(70, '-') + "\n";
cmsg.error()
<< seperator
<< "Operator createmtree: " << endl
<< "Distance function \"" << distfunName
<< "\" for type \"" << typeName
<< "\" is not defined!" << endl
<< "Defined distance functions: " << endl
<< endl
<< DistfunReg::definedNames(typeName)
<< seperator << endl;
cmsg.send();
tuple->DeleteIfAllowed();
return CANCEL;
}
if (!DistfunReg::getInfo(
distfunName, typeName, dataName).isMetric())
{
const string seperator =
"\n" + string(70, '-') + "\n";
cmsg.error()
<< seperator
<< "Operator createmtree: " << endl
<< "Distance function \"" << distfunName
<< "\" with \"" << dataName
<< "\" data for type" << endl
<< "\"" << typeName << "\" is no metric!"
<< seperator << endl;
cmsg.send();
tuple->DeleteIfAllowed();
return CANCEL;
}
mtree->initialize(
attr->distdataId(), distfunName, configName);
}
// insert attribute into mtree
char* flobData = attr->getData();
DistData *data = new DistData(attr->size(), flobData);
delete[] flobData;
mtree->insert(data, tuple->GetTupleId());
}
tuple->DeleteIfAllowed();
qp->Request(stream, wTuple);
}
qp->Close(stream);
#ifdef __MTREE_PRINT_INSERT_INFO
cout << endl;
#endif
return 0;
}
/********************************************************************
1.1.1.1 Search[_]LI
Local Info object for the search value mappings.
********************************************************************/
struct search_LI
{
Relation *relation;
list<TupleId> *results;
list<TupleId>::iterator iter;
bool defined;
search_LI(Relation *rel)
: relation(rel),
results(new list<TupleId>),
defined(false)
{}
void initResultIterator()
{
iter = results->begin();
defined = true;
}
~search_LI()
{ delete results; }
TupleId next()
{
if (iter != results->end())
{
TupleId tid = *iter;
*iter++;
return tid;
}
else
{
return 0;
}
}
};
/********************************************************************
1.1.1.1 rangesearch[_]VM
********************************************************************/
int rangesearch_VM(
Word *args, Word &result, int message,
Word &local, Supplier s)
{
search_LI *info = (search_LI*) local.addr;
switch (message)
{
case OPEN :
{
if(info){ delete info; }
MTree *mtree = static_cast<MTree*>(args[0].addr);
info = new search_LI( static_cast<Relation*>(args[1].addr));
local = SetWord(info);
Attribute *attr = static_cast<Attribute*>(args[2].addr);
double searchRad =
static_cast<CcReal*>(args[3].addr)->GetValue();
string typeName =
static_cast<CcString*>(args[4].addr)->GetValue();
if (mtree->typeName() != typeName)
{
const string seperator = "\n" + string(70, '-') + "\n";
cmsg.error() << seperator
<< "Operator rangesearch:" << endl
<< "Got an \"" << typeName << "\" attribute, but the "
<< "mtree contains \"" << mtree->typeName()
<< "\" attriubtes!" << seperator << endl;
cmsg.send();
return CANCEL;
}
mtree->rangeSearch(attr, searchRad, info->results);
info->initResultIterator();
assert(info->relation != 0);
return 0;
}
case REQUEST :
{
if(!info){ return CANCEL; }
if(!info->defined)
return CANCEL;
TupleId tid = info->next();
if(tid)
{
Tuple *tuple = info->relation->GetTuple(tid, false);
result = SetWord(tuple);
return YIELD;
}
else
{
return CANCEL;
}
}
case CLOSE :
{
if(info){
delete info;
local.addr=0;
}
return 0;
}
}
return 0;
}
/********************************************************************
1.1.1.1 rangesearchDD[_]VM
********************************************************************/
int rangesearchDD_VM(
Word *args, Word &result, int message,
Word &local, Supplier s)
{
search_LI * info = (search_LI*)local.addr;
switch (message)
{
case OPEN :
{
if(info){
delete info;
}
MTree *mtree = static_cast<MTree*>(args[0].addr);
info = new search_LI( static_cast<Relation*>(args[1].addr));
local = SetWord(info);
DistDataAttribute *attr =
static_cast<DistDataAttribute*>(args[2].addr);
double searchRad =
static_cast<CcReal*>(args[3].addr)->GetValue();
string typeName =
static_cast<CcString*>(args[4].addr)->GetValue();
if (attr->distdataId() != mtree->dataId())
{
const string seperator = "\n" + string(70, '-') + "\n";
cmsg.error() << seperator
<< "Operator rangesearch:" << endl
<< "Distdata attribute type does not match the type of "
<< "the mtree!" << seperator << endl;
cmsg.send();
return CANCEL;
}
char* flobData = attr->getData();
DistData *data = new DistData(attr->size(), flobData);
delete[] flobData;
mtree->rangeSearch(data, searchRad, info->results);
info->initResultIterator();
assert(info->relation != 0);
return 0;
}
case REQUEST :
{
if(!info){
return CANCEL;
}
if(!info->defined)
return CANCEL;
TupleId tid = info->next();
if(tid)
{
Tuple *tuple = info->relation->GetTuple(tid, false);
result = SetWord(tuple);
return YIELD;
}
else
{
return CANCEL;
}
}
case CLOSE :
{
if(info){
delete info;
local.addr = 0;
}
return 0;
}
}
return 0;
}
/********************************************************************
1.1.1.1 nnsearch[_]VM
********************************************************************/
int nnsearch_VM(
Word *args, Word &result, int message,
Word &local, Supplier s)
{
search_LI * info = (search_LI*)local.addr;
switch (message)
{
case OPEN :
{ if(info){
delete info;
}
MTree *mtree = static_cast<MTree*>(args[0].addr);
info = new search_LI( static_cast<Relation*>(args[1].addr));
local = SetWord(info);
Attribute *attr = static_cast<Attribute*>(args[2].addr);
int nncount= ((CcInt*)args[3].addr)->GetValue();
string typeName =
static_cast<CcString*>(args[4].addr)->GetValue();
if (mtree->typeName() != typeName)
{
const string seperator = "\n" + string(70, '-') + "\n";
cmsg.error() << seperator
<< "Operator nnsearch:" << endl
<< "Got an \"" << typeName << "\" attribute, but the "
<< "mtree contains \"" << mtree->typeName()
<< "\" attriubtes!" << seperator << endl;
cmsg.send();
return CANCEL;
}
mtree->nnSearch(attr, nncount, info->results);
info->initResultIterator();
assert(info->relation != 0);
return 0;
}
case REQUEST :
{
if(!info){
return CANCEL;
}
if(!info->defined)
return CANCEL;
TupleId tid = info->next();
if(tid)
{
Tuple *tuple = info->relation->GetTuple(tid, false);
result = SetWord(tuple);
return YIELD;
}
else
{
return CANCEL;
}
}
case CLOSE :
{ if(info){
delete info;
local.addr = 0;
}
return 0;
}
}
return 0;
}
/********************************************************************
1.1.1.1 nnsearchDD[_]VM
********************************************************************/
int nnsearchDD_VM(
Word *args, Word &result, int message,
Word &local, Supplier s)
{
search_LI *info = (search_LI*)local.addr;
switch (message)
{
case OPEN :
{
if(info){
delete info;
}
MTree *mtree = static_cast<MTree*>(args[0].addr);
info = new search_LI(
static_cast<Relation*>(args[1].addr));
local = SetWord(info);
DistDataAttribute *attr =
static_cast<DistDataAttribute*>(args[2].addr);
int nncount = ((CcInt*)args[3].addr)->GetValue();
if (attr->distdataId() != mtree->dataId())
{
const string seperator = "\n" + string(70, '-') + "\n";
cmsg.error() << seperator
<< "Operator nnsearch:" << endl
<< "Distdata attribute type does not match the type of "
<< "the mtree!" << seperator << endl;
cmsg.send();
return CANCEL;
}
char* flobdata = attr->getData();
DistData *data = new DistData(attr->size(), flobdata);
delete[] flobdata;
mtree->nnSearch(data, nncount, info->results);
info->initResultIterator();
assert(info->relation != 0);
return 0;
}
case REQUEST :
{
if(!info){
return CANCEL;
}
if(!info->defined)
return CANCEL;
TupleId tid = info->next();
if(tid)
{
Tuple *tuple = info->relation->GetTuple(tid, false);
result = SetWord(tuple);
return YIELD;
}
else
{
return CANCEL;
}
}
case CLOSE :
{
if(info){
delete info;
local.addr = 0;
}
return 0;
}
}
return 0;
}
/********************************************************************
1.1.1 Type mappings
1.1.1.1 createmtree[_]TM
********************************************************************/
template<unsigned paramCnt>
ListExpr createmtree_TM(ListExpr args)
{
// initialize distance functions and distdata types
if (!DistfunReg::isInitialized())
DistfunReg::initialize();
NList args_NL(args);
if(!args_NL.hasLength(paramCnt)){
stringstream err;
err << "Expecting " << paramCnt << " argument(s)!";
return listutils::typeError(err.str());
}
NList attrs;
NList relStream_NL = args_NL.first();
NList attr_NL = args_NL.second();
if(!relStream_NL.checkRel(attrs) && !relStream_NL.checkStreamTuple(attrs)){
return listutils::typeError(
"Argument 1 must be a relation or tuple stream!");
}
// check, if the specified attribute can be found in attribute list
if(!attr_NL.isSymbol()){
return listutils::typeError(
"Argument 2 must be a symbol or an atomar type!");
}
string attrName = attr_NL.str();
string typeName;
int attrIndex;
ListExpr attrTypeLE;
attrIndex = FindAttribute(attrs.listExpr(), attrName, attrTypeLE);
if(attrIndex <= 0){
stringstream err;
err << "Attribute name \"" << attrName << "\" is not known.\n"
<< "Known Attribute(s):\n" << attrs.convertToString();
return listutils::typeError(err.str());
}
--attrIndex;
NList attrType (attrTypeLE);
typeName = attrType.str();
if (paramCnt > 3)
{
string errmsg = "No distdata attributes allowed for operator"
"createmtree3 - use createmtree or createmtree2 instead)!";
if(typeName == "distdata"){
return listutils::typeError(errmsg);
}
}
// get config name
string configName;
if (paramCnt >= 3){
if(!args_NL.third().isSymbol()){
listutils::typeError(
"Argument 3 must be the name of an existing config object!");
}
configName = args_NL.third().str();
}
else
configName = CONFIG_DEFAULT;
if (!MTreeConfigReg::isDefined(configName))
{
string errmsg;
errmsg = "Config \"" + configName +
"\" not defined, defined names:\n\n" +
MTreeConfigReg::definedNames();
return listutils::typeError(errmsg);
}
// select distfun name
string distfunName;
if (paramCnt >= 4){
if(!args_NL.fourth().isSymbol()){
stringstream err;
err << "Argument 4 must be the name of an existing "
<< "distance function or \"" + DFUN_DEFAULT + "\"!";
return listutils::typeError(err.str());
}
distfunName = args_NL.fourth().str();
}
else
distfunName = DFUN_DEFAULT;
if (typeName == "distdata")
{
NList res1(Symbol::APPEND());
NList res2;
res2.append(NList(attrIndex));
res2.append(NList(distfunName, true));
res2.append(NList(configName, true));
NList res3(MTree::BasicType());
NList result(res1, res2, res3);
return result.listExpr();
}
// *** typeName != "distdata" ***
// select distdata type
string dataName;
if (paramCnt >= 5){
if(!args_NL.fifth().isSymbol()){
stringstream err;
err << "Argument 5 must be the name of an existing "
<< "distdata type or \"" + DDATA_DEFAULT + "\"!";
return listutils::typeError(err.str());
}
dataName = args_NL.fifth().str();
}
else
dataName = DistDataReg::defaultName(typeName);
// check, if selected distdata type is defined
if (dataName == DDATA_DEFAULT){
dataName = DistDataReg::defaultName(typeName);
if(dataName == DDATA_UNDEFINED){
string errmsg;
errmsg = "No default distdata type defined for type "
"constructor \"" + typeName + "\"!";
return listutils::typeError(errmsg);
}
} else if(!DistDataReg::isDefined(typeName, dataName)){
string errmsg;
errmsg = "Distdata type \"" + dataName + "\" for "
"type constructor \"" + typeName +
"\" is not defined! Defined names: \n\n" +
DistDataReg::definedNames(typeName);
return listutils::typeError(errmsg);
}
// Returs a type error, if the specified distance function is not defined.
string errmsg;
if (distfunName == DFUN_DEFAULT){
distfunName = DistfunReg::defaultName(typeName);
if(distfunName == DFUN_UNDEFINED){
errmsg = "No default distance function defined for type \""
+ typeName + "\"!";
return listutils::typeError(errmsg);
}
} else {
if (!DistfunReg::isDefined(distfunName, typeName, dataName)){
errmsg = "Distance function \"" + distfunName +
"\" not defined for type \"" +
typeName + "\" and data type \"" +
dataName + "\"! Defined names: \n\n" +
DistfunReg::definedNames(typeName);
return listutils::typeError(errmsg);
}
}
// check if selected distance function is a metric
if(!DistfunReg::getInfo(distfunName, typeName, dataName).isMetric()){
errmsg = "Distance function \"" + distfunName +
"\" with \"" + dataName + "\" data for type \"" +
typeName + "\" is no metric!";
return listutils::typeError(errmsg);
}
// generate result list
NList res1(Symbol::APPEND());
NList res2;
res2.append(NList(attrIndex));
res2.append(NList(typeName, true));
res2.append(NList(distfunName, true));
res2.append(NList(dataName, true));
res2.append(NList(configName, true));
NList res3(MTree::BasicType());
NList result(res1, res2, res3);
return result.listExpr();
}
/********************************************************************
1.3.2.4 rangesearch[_]TM
********************************************************************/
ListExpr rangesearch_TM(ListExpr args)
{
// initialize distance functions and distdata types
if (!DistfunReg::isInitialized())
DistfunReg::initialize();
NList args_NL(args);
if(!args_NL.hasLength(4)){
return listutils::typeError("Expecting 4 argument(s)!");
}
NList attrs;
NList mtree_NL = args_NL.first();
NList rel_NL = args_NL.second();
NList data_NL = args_NL.third();
NList searchRad_NL = args_NL.fourth();
if(!mtree_NL.isEqual(MTree::BasicType())){
return listutils::typeError("First argument must be a mtree!");
}
if(!rel_NL.checkRel(attrs)){
return listutils::typeError("Argument 2 must be a relation!");
}
if(!data_NL.isSymbol()){
return listutils::typeError(
"Argument 3 must be a symbol or an atomar type!");
}
if(!searchRad_NL.isEqual(CcReal::BasicType())){
return listutils::typeError("Argument 4 must be a \"real\" value!");
}
/* Further type checkings for the data parameter will be done
in the value mapping function, since the type of the mtree
is not yet known. */
NList append(Symbol::APPEND());
NList result (
append,
NList(data_NL.str(), true).enclose(),
NList(NList(Symbol::STREAM()), rel_NL.second()));
return result.listExpr();
}
/********************************************************************
1.3.2.5 nnsearch[_]TM
********************************************************************/
ListExpr nnsearch_TM(ListExpr args)
{
// initialize distance functions and distdata types
if (!DistfunReg::isInitialized())
DistfunReg::initialize();
NList args_NL(args);
if(!args_NL.hasLength(4)){
stringstream err;
return listutils::typeError("Expecting 4 arguments!");
}
NList attrs;
NList mtree_NL = args_NL.first();
NList rel_NL = args_NL.second();
NList data_NL = args_NL.third();
NList nnCount_NL = args_NL.fourth();
if(!mtree_NL.isEqual(MTree::BasicType())){
return listutils::typeError("First argument must be a mtree!");
}
if(!rel_NL.checkRel(attrs)){
return listutils::typeError("Argument 2 must be a relation!");
}
if(!data_NL.isSymbol()){
return listutils::typeError(
"Argument 3 must be a symbol or an atomar type!");
}
if(!nnCount_NL.isEqual(CcInt::BasicType())){
return listutils::typeError("Argument 4 must be an \"int\" value!");
}
/* Further type checkings for the data parameter will be done
in the value mapping function, since the type of the mtree
is not yet known. */
NList append(Symbol::APPEND());
NList result (
append,
NList(data_NL.str(), true).enclose(),
NList(NList(Symbol::STREAM()), rel_NL.second()));
return result.listExpr();
}
/********************************************************************
1.3.3 Selection functions
********************************************************************/
int createmtree_Select(ListExpr args)
{
NList argsNL(args);
NList arg1 = argsNL.first();
NList attrs = arg1.second().second();
NList arg2 = argsNL.second();
// get type of selected attribute
string attrName = arg2.str();
ListExpr attrTypeLE;
FindAttribute(attrs.listExpr(), attrName, attrTypeLE);
NList attrType(attrTypeLE);
if (arg1.first().isEqual(Relation::BasicType()))
{
if(attrType.isEqual("distdata"))
return 2;
else
return 0;
}
else if (arg1.first().isEqual(Symbol::STREAM()))
{
if(attrType.isEqual("distdata"))
return 3;
else
return 1;
}
else
return -1;
}
int createmtree3_Select(ListExpr args)
{
NList argsNL(args);
NList arg1 = argsNL.first();
if (arg1.first().isEqual(Relation::BasicType()))
return 0;
else if (arg1.first().isEqual(Symbol::STREAM()))
return 1;
else
return -1;
}
int search_Select(ListExpr args)
{
NList argsNL(args);
NList arg3 = argsNL.third();
if (arg3.isEqual("distdata"))
return 1;
else
return 0;
}
/********************************************************************
1.3.4 Value mapping arrays
********************************************************************/
ValueMapping createmtree_Map[] = {
createmtreeRel_VM<2>,
createmtreeStream_VM<2>,
createmtreeDDRel_VM<2>,
createmtreeDDStream_VM<2>
};
ValueMapping createmtree2_Map[] = {
createmtreeRel_VM<3>,
createmtreeStream_VM<3>,
createmtreeDDRel_VM<3>,
createmtreeDDStream_VM<3>
};
ValueMapping createmtree3_Map[] = {
createmtreeRel_VM<5>,
createmtreeStream_VM<5>
};
ValueMapping rangesearch_Map[] = {
rangesearch_VM,
rangesearchDD_VM
};
ValueMapping nnsearch_Map[] = {
nnsearch_VM,
nnsearchDD_VM
};
/********************************************************************
1.3.5 Operator infos
********************************************************************/
struct createmtree_Info : OperatorInfo
{
createmtree_Info()
{
name = "createmtree";
signature =
"relation/tuple stream x attribute -> mtree";
syntax = "_ createmtree [_]";
meaning =
"Creates a new mtree from the relation or tuple stream "
"in argument 1. Argument 2 must be the name of the "
"attribute in the relation/tuple stream, that should "
"be indexed in the mtree. "
"This operator uses the default mtree config and the "
"default metric for the type constructor of the "
"specified attribute (the distdata type is specified "
"by the expected distdata type of the default metric).";
example = "Orte createmtree[Ort]";
}
};
struct createmtree2_Info : OperatorInfo
{
createmtree2_Info()
{
name = "createmtree2";
signature =
"relation/tuple stream x attribute x config_name -> mtree";
syntax = "_ createmtree2 [_, _, _]";
meaning =
"Creates a new mtree from the relation or tuple stream "
"in argument 1. Argument 2 must be the name of the "
"attribute in the relation/tuple stream, that should "
"be indexed in the mtree. config_name must be the name "
"of a registered mtree configuration."
"This operator uses the default distdata type for the "
"type constructor of the specified attribute.";
example = "Orte createmtree2 [Ort, limit80e]";
}
};
struct createmtree3_Info : OperatorInfo
{
createmtree3_Info()
{
name = "createmtree3";
signature =
"relation/tuple stream x attribute x config_name x "
"metric_name x distdata_name -> mtree";
syntax = "_ createmtree3 [_, _, _, _]";
meaning =
"Creates a new mtree from the relation or tuple stream "
"in argument 1. Argument 2 must be the name of the "
"attribute in the relation/tuple stream, that should "
"be indexed in the mtree. config_name must be the name "
"of a registered mtree configuration. metric_name must "
"be the name of a defined metric and distdata_name must "
"be the name of a registered distdata type.";
example =
"Orte createmtree3 [Ort, limit80e, edit, native]";
}
};
struct rangesearch_Info : OperatorInfo
{
rangesearch_Info()
{
name = "rangesearch";
signature = "mtree x relation x DATA x real -> tuple stream";
syntax = "_ _ rangesearch [_, _]";
meaning =
"Returns a tuple stream, which contains all attributes, "
"that could be found within the search radius "
"(argument 4) to the query data (argument 3). The "
"relation must contain at least the same tuples, that "
"has been used to create the mtree. ";
example = "pictree pictures rangesearch [pic1, 0.2]";
}
};
struct nnsearch_Info : OperatorInfo
{
nnsearch_Info()
{
name = "nnsearch";
signature = "mtree x relation x DATA x int -> tuple stream";
syntax = "_ _ nnsearch [_, _]";
meaning =
"Returns a tuple stream, which contains the k nearest "
"neighbours of the query data (argument 3), whereas "
"k is specified in argument 4. The relation must "
"contain at least the same tuples, that has been used "
"to create the mtree. ";
example = "pictree pictures nnsearch [pic1, 5]";
}
};
/********************************************************************
1.4 Create and initialize the Algebra
********************************************************************/
class MTreeAlgebra
: public Algebra
{
public:
MTreeAlgebra()
: Algebra()
{
AddTypeConstructor(&mtreeTC);
AddOperator(createmtree_Info(),
createmtree_Map,
createmtree_Select,
createmtree_TM<2>);
AddOperator(createmtree2_Info(),
createmtree2_Map,
createmtree_Select,
createmtree_TM<3>);
AddOperator(createmtree3_Info(),
createmtree3_Map,
createmtree_Select,
createmtree_TM<5>);
AddOperator(rangesearch_Info(),
rangesearch_Map,
search_Select,
rangesearch_TM);
AddOperator(nnsearch_Info(),
nnsearch_Map,
search_Select,
nnsearch_TM);
}
~MTreeAlgebra()
{};
};
} // namespace mtreeAlgebra
extern "C"
Algebra *InitializeMTreeAlgebra(
NestedList *nlRef, QueryProcessor *qpRef)
{
nl = nlRef;
qp = qpRef;
return new mtreeAlgebra::MTreeAlgebra();
}