Upgrade to Pro — share decks privately, control downloads, hide ads and more …

A Report by Any Other Name

A Report by Any Other Name

Student Success Plan (SSP) is exploring alternatives to its current reporting subsystem (Hibernate+Jasper). Along the way, developers have found themselves asking "What is a 'report' anyway"? What makes a "report" different from any other UI-rendered application feature? This presentation will discuss distinctions and tradeoffs between several different approaches to thinking about and implementing report-ish features with a special emphasis on OLAP-backed report delivery, all based on the SSP development team's efforts to make its reports more useful and usable for both developers and end users.

#apereo13

dmccallum

June 06, 2013
Tweet

More Decks by dmccallum

Other Decks in Programming

Transcript

  1. A report by Any other name ...would probably be just

    another app screen Thursday, June 6, 13
  2. Overview • Intro • Reports Defined (or not) • Reports

    in SSP (w/o OLAP) • Reports in SSP (w/ OLAP) • Reports Defined (or not) Thursday, June 6, 13
  3. “According to Sinclair statistics from 2005 – 2011, students using

    SSP were five times more likely to graduate. For quarter to quarter retention rates ... transitioned SSP students ... had a 37% higher rate of retention compared to students who qualified for the program but did not participate and a 26% higher rate of retention than students not designated “at risk”. http://www.studentsuccessplan.org/index.php?option=com_content&view=article&id=81:ssphistory&catid=43:main&Itemid=110 Thursday, June 6, 13
  4. select p.first_name, p.last_name, p.school_id student_id, isnull(ms.name, 'UNKNOWN') marital_status, isnull(pd.gender, 'UNKNOWN')

    gender, isnull(c.name, 'UNKNOWN') citizenship, isnull(vs.name, 'UNKNOWN') veteran_status, primary_caregiver = case when pd.primary_caregiver is null then 'UNKNOWN' when pd.primary_caregiver = 1 then 'YES' else 'NO' end, isnull(ss.name, 'UNKNOWN') student_status, orientation_complete = case when pep.new_orientation_complete is null then 'UNKNOWN' when pep.new_orientation_complete = 1 then 'YES' else 'NO' end, registered = case when pep.registered_for_classes is null then 'UNKNOWN' when pep.registered_for_classes = 1 then 'YES' else 'NO' end, isnull(pel_view.pel_el, 'UNKNOWN') education_level, isnull(eg.name, 'UNKNOWN') education_goal, planned_major = case when peg.planned_major is null then 'UNKNOWN' when peg.planned_major = '' then 'UNKNOWN' else peg.planned_major end, isnull(peg.how_sure_about_major, -1) major_surety__1_unsure_5_sure, career_decided = case when peg.career_decided is null then 'UNKNOWN' when peg.career_decided = 1 then 'YES' else 'NO' end, planned_occupation = case when peg.planned_occupation is null then 'UNKNOWN' when peg.planned_occupation = '' then 'UNKNOWN' else peg.planned_occupation end, isnull(peg.how_sure_about_occupation, -1) occupation_surety__1_unsure_5_sure, confident_in_abilities = case when peg.confident_in_abilities is null then 'UNKNOWN' when peg.confident_in_abilities = 1 then 'YES' else 'NO' end, need_program_info = case when peg.additional_academic_program_information_needed is null then 'UNKNOWN' when peg.additional_academic_program_information_needed = 1 then 'YES' else 'NO' end, isnull(pfs_view.pfs_fs, 'UNKNOWN') funding_source from person p left outer join person_demographics pd on p.person_demographics_id = pd.id and pd.object_status = 1 left outer join marital_status ms on pd.marital_status_id = ms.id left outer join citizenship c on pd.citizenship_id = c.id left outer join veteran_status vs on pd.veteran_status_id = vs.id left outer join person_education_plan pep on p.person_education_plan_id = pep.id and pep.object_status = 1 left outer join student_status ss on pep.student_status_id = ss.id left outer join (select pel1.person_id, left(pel1.pel_el, LEN(pel1.pel_el) - 1) pel_el from (select distinct pel.person_id, (select el.name + ',' as [text()] from education_level el join person_education_level pel2 on pel2.education_level_id = el.id where pel2.person_id = pel.person_id for xml path ('')) pel_el from person_education_level pel where pel.object_status = 1) pel1) pel_view on pel_view.person_id = p.id left outer join person_education_goal peg on p.person_education_goal_id = peg.id and peg.object_status = 1 left outer join education_goal eg on peg.education_goal_id = eg.id left outer join (select pfs1.person_id, left(pfs1.pfs_fs, LEN(pfs1.pfs_fs) - 1) pfs_fs from (select distinct pfs.person_id, (select fs.name + ',' as [text()] from funding_source fs join person_funding_source pfs2 on pfs2.funding_source_id = fs.id where pfs2.person_id = pfs.person_id for xml path ('')) pfs_fs from person_funding_source pfs where pfs.object_status = 1) pfs1) pfs_view on pfs_view.person_id = p.id where p.student_type_id is not null order by p.last_name, p.first_name https://gist.github.com/dmccallum/4708795 Thursday, June 6, 13
  5. ETL ETL Mondrian MDX QUERY MDX->Relational Mapper Execution/ Cache DB

    CUBE DEFS (Schema) ETL Thursday, June 6, 13
  6. MyOtherDim.1 MyOtherDim.1 MyOtherDim.2 MyOtherDim.2 Measure.1 Measure.2 Measure.1 Measure.2 MyDim.1 MyDim.2

    MyDim.3 1.09 822 9.01 8811 3.67 676 4.02 2311 8.00 129 0.33 109 Thursday, June 6, 13
  7. Event Source 1 Event Source 1 Event Source 2 Event

    Source 2 Latency (Avg) Count Latency (Avg) Count Jan Feb Mar 1.09 822 9.01 8811 3.67 676 4.02 2311 8.00 129 0.33 109 Thursday, June 6, 13
  8. <Schema name="New Schema2"> <Cube name="Current Caseload" visible="true" cache="true" enabled="true"> <Table

    name="current_student_fact" schema="public"> </Table> <Dimension type="StandardDimension" visible="true" foreignKey="student_id" highCardinality="false" name="Student"> <Hierarchy name="Student" visible="true" hasAll="true" allMemberName="All Students" primaryKey="id"> <Table name="student" schema="public"> </Table> <Level name="Student" visible="true" table="student" column="id" nameColumn="full_name" ordinalColumn="full_name" type="Integer" uniqueMembers="true" levelType="Regular" hideMemberIf="Never"> </Level> </Hierarchy> </Dimension> <Dimension type="StandardDimension" visible="true" foreignKey="coach_id" highCardinality="false" name="Coach"> <Hierarchy name="Coach" visible="true" hasAll="true" allMemberName="All Coaches" primaryKey="id"> <Table name="coach" schema="public"> </Table> <Level name="Coach" visible="true" table="coach" column="id" nameColumn="full_name" ordinalColumn="full_name" type="Integer" uniqueMembers="true" levelType="Regular" hideMemberIf="Never"> </Level> </Hierarchy> </Dimension> <Dimension type="StandardDimension" visible="true" foreignKey="program_status_id" highCardinality="false" name="Program Status"> <Hierarchy name="Program Status" visible="true" hasAll="true" allMemberName="All Program Statuses"> <Table name="program_status" schema="public"> </Table> <Level name="Program Status" visible="true" table="program_status" column="id" nameColumn="display_name" ordinalColumn="display_name" type="Integer" uniqueMembers="true" levelType="Regular" hideMemberIf="Never"> </Level> </Hierarchy> </Dimension> <Measure name="Count" column="cnt" datatype="Integer" aggregator="sum" visible="true"> </Measure> </Cube> </Schema> Thursday, June 6, 13
  9. But OLAP will be enough to chew on for a

    while... Thursday, June 6, 13