Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
olapy
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
2
Merge Requests
2
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
nexedi
olapy
Commits
64486df0
Commit
64486df0
authored
Mar 17, 2017
by
Stefane Fermigier
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
"On rows".
parent
26bd503c
Changes
5
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
439 additions
and
255 deletions
+439
-255
olapy/core/mdx/executor/execute.py
olapy/core/mdx/executor/execute.py
+78
-32
olapy/core/services/xmla.py
olapy/core/services/xmla.py
+20
-13
olapy/core/services/xmla_discover_tools.py
olapy/core/services/xmla_discover_tools.py
+69
-47
olapy/core/services/xmla_execute_tools.py
olapy/core/services/xmla_execute_tools.py
+272
-161
tests/test_xmla_notox.py
tests/test_xmla_notox.py
+0
-2
No files found.
olapy/core/mdx/executor/execute.py
View file @
64486df0
...
@@ -127,6 +127,23 @@ class MdxEngine:
...
@@ -127,6 +127,23 @@ class MdxEngine:
"""
"""
return
os
.
path
.
join
(
self
.
cube_path
,
self
.
cube
)
return
os
.
path
.
join
(
self
.
cube_path
,
self
.
cube
)
# TODO temporary function
def
get_tuples
(
self
,
query
,
start
=
None
,
stop
=
None
):
# TODO use grako instead and remove regex
regex
=
"(
\
[[
\
w
\
d ]+
\
](
\
.
\
[[
\
w
\
d
\
.
\
- ]+
\
])*
\
.?((Members)|(
\
[Q
\
d
\
]))?)
"
if start is not None:
start = query.index(start)
if stop is not None:
stop = query.index(stop)
# clean the query (from All, Members...)
return [[
tup_att.replace('All ', '').replace('[', "").replace("
]
", "")
for tup_att in tup[0].replace('.Members', '').split('.')
] for tup in re.compile(regex).findall(query[start:stop])
if len(tup[0].split('.')) > 1]
# TODO temporary function
# TODO temporary function
def decorticate_query(self, query):
def decorticate_query(self, query):
"""
"""
...
@@ -135,16 +152,38 @@ class MdxEngine:
...
@@ -135,16 +152,38 @@ class MdxEngine:
:return: all tuples in the query
:return: all tuples in the query
"""
"""
# TODO use grako instead and remove regex
tuples_on_mdx_query = self.get_tuples(query)
regex
=
"(
\
[[
\
w
\
d ]+
\
](
\
.
\
[[
\
w
\
d
\
.
\
- ]+
\
])*
\
.?((Members)|(
\
[Q
\
d
\
]))?)
"
# clean the query
on_rows = []
tuples_on_mdx_query = [[
on_columns = []
tup_att.replace('All ', '').replace('[', "").replace("
]
", "")
on_where = []
for tup_att in tup[0].replace('.Members', '').split('.')
] for tup in re.compile(regex).findall(query)
if len(tup[0].split('.')) > 1]
return tuples_on_mdx_query
# ON ROWS
if 'ON ROWS' in query:
stop = 'ON ROWS'
if 'ON COLUMNS' in query:
start = 'ON COLUMNS'
else:
start = 'SELECT'
on_rows = self.get_tuples(query, start, stop)
# ON COLUMNS
if 'ON COLUMNS' in query:
start = 'SELECT'
stop = 'ON COLUMNS'
on_columns = self.get_tuples(query, start, stop)
# WHERE
if 'WHERE' in query:
start = 'FROM'
on_where = self.get_tuples(query, start)
return {
'all': tuples_on_mdx_query,
'columns': on_columns,
'rows': on_rows,
'where': on_where
}
def change_measures(self, tuples_on_mdx):
def change_measures(self, tuples_on_mdx):
"""
"""
...
@@ -161,6 +200,7 @@ class MdxEngine:
...
@@ -161,6 +200,7 @@ class MdxEngine:
]
]
def get_tables_and_columns(self, tuple_as_list):
def get_tables_and_columns(self, tuple_as_list):
# TODO update docstring
"""
"""
get used dimensions and columns in the MDX Query (useful for DataFrame -> xmla response transformation)
get used dimensions and columns in the MDX Query (useful for DataFrame -> xmla response transformation)
...
@@ -178,23 +218,31 @@ class MdxEngine:
...
@@ -178,23 +218,31 @@ class MdxEngine:
Facts : ['Amount','Count']
Facts : ['Amount','Count']
}
}
"""
"""
tables_columns = OrderedDict()
axes = {}
# TODO optimize
# TODO optimize
measures = []
for axis, tuples in tuple_as_list.items():
for tupl in tuple_as_list:
measures = []
tables_columns = OrderedDict()
# if we have measures in columns or rows axes like :
# if we have measures in columns or rows axes like :
# SELECT {[Measures].[Amount],[Measures].[Count]} ON COLUMNS
# SELECT {[Measures].[Amount],[Measures].[Count]} ON COLUMNS
# we have to add measures directly to tables_columns
# we have to add measures directly to tables_columns
if tupl[0].upper() == 'MEASURES':
for tupl in tuples:
measures.append(tupl[-1])
if tupl[0].upper() == 'MEASURES':
tables_columns.update({self.facts: measures})
if tupl[-1] not in measures:
else:
measures.append(tupl[-1])
tables_columns.update({
tables_columns.update({self.facts: measures})
tupl[0]:
else:
self.tables_loaded[tupl[0]].columns[:len(tupl[2:])]
continue
})
else:
tables_columns.update({
return tables_columns
tupl[0]:
self.tables_loaded[tupl[0]].columns[:len(tupl[2:])]
})
axes.update({axis: tables_columns})
return axes
def execute_one_tuple(self, tuple_as_list, Dataframe_in, columns_to_keep):
def execute_one_tuple(self, tuple_as_list, Dataframe_in, columns_to_keep):
"""
"""
...
@@ -397,24 +445,21 @@ class MdxEngine:
...
@@ -397,24 +445,21 @@ class MdxEngine:
"""
"""
# use measures that exists on where or insides axes
# use measures that exists on where or insides axes
all_tupl
es = self.decorticate_query(self.mdx_query)
query_ax
es = self.decorticate_query(self.mdx_query)
if self.change_measures(
all_tuples
):
if self.change_measures(
query_axes['all']
):
self.measures = self.change_measures(
all_tuples
)
self.measures = self.change_measures(
query_axes['all']
)
# get only used columns and dimensions for all query
# get only used columns and dimensions for all query
start_df = self.load_star_schema_dataframe
start_df = self.load_star_schema_dataframe
tables_n_columns = self.get_tables_and_columns(
all_tupl
es)
tables_n_columns = self.get_tables_and_columns(
query_ax
es)
columns_to_keep = {
columns_to_keep = OrderedDict(
table: columns
(table, columns) for table, columns in tables_n_columns['all'].items() if table != self.facts)
for table, columns in tables_n_columns.items()
if table != self.facts
}
# if we have measures on axes we have to ignore them
# if we have measures on axes we have to ignore them
tuples_on_mdx_query = [
tuples_on_mdx_query = [
tup for tup in
all_tuples
if tup[0].upper() != 'MEASURES'
tup for tup in
query_axes['all']
if tup[0].upper() != 'MEASURES'
]
]
# if we have tuples in axes
# if we have tuples in axes
# to avoid prob with query like this: SELECT FROM [Sales] WHERE ([Measures].[Amount])
# to avoid prob with query like this: SELECT FROM [Sales] WHERE ([Measures].[Amount])
...
@@ -469,6 +514,7 @@ class MdxEngine:
...
@@ -469,6 +514,7 @@ class MdxEngine:
df = pd.concat(self.add_missed_column(df, next_df))
df = pd.concat(self.add_missed_column(df, next_df))
# TODO groupby in web demo (remove it for more performance)
# TODO groupby in web demo (remove it for more performance)
# TODO margins=True for columns total !!!!!
return {
return {
'result':
'result':
df.drop_duplicates().replace(np.nan, -1).groupby(cols).sum(),
df.drop_duplicates().replace(np.nan, -1).groupby(cols).sum(),
...
...
olapy/core/services/xmla.py
View file @
64486df0
...
@@ -81,22 +81,27 @@ class XmlaProviderService(ServiceBase):
...
@@ -81,22 +81,27 @@ class XmlaProviderService(ServiceBase):
return
discover_tools
.
discover_mdschema_measures__response
(
request
)
return
discover_tools
.
discover_mdschema_measures__response
(
request
)
elif
request
.
RequestType
==
"MDSCHEMA_DIMENSIONS"
:
elif
request
.
RequestType
==
"MDSCHEMA_DIMENSIONS"
:
return
discover_tools
.
discover_mdschema_dimensions_response
(
request
)
return
discover_tools
.
discover_mdschema_dimensions_response
(
request
)
elif
request
.
RequestType
==
"MDSCHEMA_HIERARCHIES"
:
elif
request
.
RequestType
==
"MDSCHEMA_HIERARCHIES"
:
return
discover_tools
.
discover_mdschema_hierarchies_response
(
request
)
return
discover_tools
.
discover_mdschema_hierarchies_response
(
request
)
elif
request
.
RequestType
==
"MDSCHEMA_LEVELS"
:
elif
request
.
RequestType
==
"MDSCHEMA_LEVELS"
:
return
discover_tools
.
discover_mdschema_levels__response
(
request
)
return
discover_tools
.
discover_mdschema_levels__response
(
request
)
elif
request
.
RequestType
==
"MDSCHEMA_MEASUREGROUPS"
:
elif
request
.
RequestType
==
"MDSCHEMA_MEASUREGROUPS"
:
return
discover_tools
.
discover_mdschema_measuresgroups_response
(
request
)
return
discover_tools
.
discover_mdschema_measuresgroups_response
(
request
)
elif
request
.
RequestType
==
"MDSCHEMA_MEASUREGROUP_DIMENSIONS"
:
elif
request
.
RequestType
==
"MDSCHEMA_MEASUREGROUP_DIMENSIONS"
:
return
discover_tools
.
discover_mdschema_measuresgroups_dimensions_response
(
request
)
return
discover_tools
.
discover_mdschema_measuresgroups_dimensions_response
(
request
)
elif
request
.
RequestType
==
"MDSCHEMA_PROPERTIES"
:
elif
request
.
RequestType
==
"MDSCHEMA_PROPERTIES"
:
return
discover_tools
.
discover_mdschema_properties_response
(
request
)
return
discover_tools
.
discover_mdschema_properties_response
(
request
)
elif
request
.
RequestType
==
"MDSCHEMA_MEMBERS"
:
elif
request
.
RequestType
==
"MDSCHEMA_MEMBERS"
:
return
discover_tools
.
discover_mdschema_members_response
(
request
)
return
discover_tools
.
discover_mdschema_members_response
(
request
)
...
@@ -127,7 +132,8 @@ class XmlaProviderService(ServiceBase):
...
@@ -127,7 +132,8 @@ class XmlaProviderService(ServiceBase):
</return>
</return>
"""
)
"""
)
else
:
else
:
XmlaProviderService
.
discover_tools
.
change_catalogue
(
request
.
Properties
.
PropertyList
.
Catalog
)
XmlaProviderService
.
discover_tools
.
change_catalogue
(
request
.
Properties
.
PropertyList
.
Catalog
)
executer
=
XmlaProviderService
.
discover_tools
.
executer
executer
=
XmlaProviderService
.
discover_tools
.
executer
executer
.
mdx_query
=
request
.
Command
.
Statement
executer
.
mdx_query
=
request
.
Command
.
Statement
df
=
executer
.
execute_mdx
()
df
=
executer
.
execute_mdx
()
...
@@ -143,33 +149,34 @@ class XmlaProviderService(ServiceBase):
...
@@ -143,33 +149,34 @@ class XmlaProviderService(ServiceBase):
<Cube>
<Cube>
<CubeName>Sales</CubeName>
<CubeName>Sales</CubeName>
<LastDataUpdate
<LastDataUpdate
xmlns="http://schemas.microsoft.com/analysisservices/2003/engine">{
6
}</LastDataUpdate>
xmlns="http://schemas.microsoft.com/analysisservices/2003/engine">{
7
}</LastDataUpdate>
<LastSchemaUpdate
<LastSchemaUpdate
xmlns="http://schemas.microsoft.com/analysisservices/2003/engine">{
6
}</LastSchemaUpdate>
xmlns="http://schemas.microsoft.com/analysisservices/2003/engine">{
7
}</LastSchemaUpdate>
</Cube>
</Cube>
</CubeInfo>
</CubeInfo>
<AxesInfo>
<AxesInfo>
{1}
{1}
</AxesInfo>
{2}
{2}
</AxesInfo>
{3}
</OlapInfo>
</OlapInfo>
<Axes>
<Axes>
{3}
{4}
{4}
{5}
</Axes>
</Axes>
<CellData>
<CellData>
{
5
}
{
6
}
</CellData>
</CellData>
</root>
</root>
</return>
</return>
"""
.
format
(
execute_xsd
,
"""
.
format
(
execute_xsd
,
xmla_tools
.
generate_axes_info
(
df
),
xmla_tools
.
generate_axes_info
(
df
),
xmla_tools
.
generate_axes_info_slicer
(
df
),
xmla_tools
.
generate_cell_info
(),
xmla_tools
.
generate_cell_info
(),
xmla_tools
.
generate_xs0
(
df
),
xmla_tools
.
generate_xs0
(
df
),
xmla_tools
.
generate_slicer_axis
(
df
),
xmla_tools
.
generate_slicer_axis
(
df
),
xmla_tools
.
generate_cell_data
(
df
),
xmla_tools
.
generate_cell_data
(
df
),
datetime
.
now
().
strftime
(
'%Y-%m-%dT%H:%M:%S'
)
datetime
.
now
().
strftime
(
'%Y-%m-%dT%H:%M:%S'
)))
))
application
=
Application
(
application
=
Application
(
...
...
olapy/core/services/xmla_discover_tools.py
View file @
64486df0
This diff is collapsed.
Click to expand it.
olapy/core/services/xmla_execute_tools.py
View file @
64486df0
This diff is collapsed.
Click to expand it.
tests/test_xmla_notox.py
View file @
64486df0
...
@@ -266,8 +266,6 @@ def test_query2(conn):
...
@@ -266,8 +266,6 @@ def test_query2(conn):
DisplayInfo
=
'131076'
,
DisplayInfo
=
'131076'
,
PARENT_UNIQUE_NAME
=
'[Geography].[Geography].[Continent].[Europe]'
,
PARENT_UNIQUE_NAME
=
'[Geography].[Geography].[Continent].[Europe]'
,
HIERARCHY_UNIQUE_NAME
=
'[Geography].[Geography]'
))
HIERARCHY_UNIQUE_NAME
=
'[Geography].[Geography]'
))
print
([
Member
(
**
dict
(
co
))
for
co
in
columns
])
print
(
mems
)
assert
[
Member
(
**
dict
(
co
))
for
co
in
columns
]
==
mems
assert
[
Member
(
**
dict
(
co
))
for
co
in
columns
]
==
mems
assert
values
==
[
768
,
768
,
768
,
255
,
4
,
3
,
2
,
1
,
248
]
assert
values
==
[
768
,
768
,
768
,
255
,
4
,
3
,
2
,
1
,
248
]
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment