-
웹알못의 데이터 어드민 사이트 만들기(feat. Streamlit) 2. 페이지 작성etc. 2022. 9. 10. 01:00
Streamlit을 띄운 목적이 데이터 애드혹을 줄이는 것이었기 때문에,
주요 테이블을 조회하는 간단한 쿼리를 누구나 클릭 베이스로 작성할 수 있는 페이지를 가장 먼저 작성해 봤습니다.
부끄럽지만 전체 코드(일부를 제외한) 를 첨부합니다.
더보기import streamlit as st import pandas as pd from datetime import datetime, timedelta st.set_page_config(page_title="queryMaker", page_icon="📝", layout='wide') st.title("dat-a-dmin [queryMaker]") ### d0_options = { "유저, 크리에이터": [""], "마케팅": [""], "사이트/앱 로그": [""], "매출": [""], "구독": [""], "글로벌": [""], "클래스, 키트, 스토어": [""], "기타": [None] } d0_tu = tuple(d0_options.keys()) depth0 = st.selectbox( '어떤 데이터가 필요하신가요?', d0_tu ) @st.cache(ttl=10800) def get_tables(tablename): engine = db.ps_engine() schemas = pd.read_sql(f"desc {tablename}", con=engine) return schemas d0_result = (d0_options.get(depth0)) depth1 = st.selectbox( label='어떤 테이블을 확인해 볼까요?', options=tuple(d0_result), ) if depth1==None: st.warning("데이터 팀에 문의해 주세요!") else: sc = get_tables(depth1) depth2 = st.multiselect( '어떤 조건이 필요한가요? (복수 선택)', ['날짜 범위', '숫자 범위', '특정 텍스트 포함', 'T/F'] ) try: num_col = sc.loc[(sc['Type'].str.contains('int'))|(sc['Type']=='double')|(sc['Type'].str.contains('decimal')), 'Column'] date_col = sc.loc[(sc['Type']=='date')|(sc['Type'].str.contains('timestamp')), 'Column'] text_col = sc.loc[(sc['Type'].str.contains('varchar')), 'Column'] bool_col = sc.loc[(sc['Type']=='boolean'), 'Column'] d2_options = { "날짜 범위": date_col, "숫자 범위": num_col, "특정 텍스트 포함": text_col, "T/F": bool_col } where_sentence = "where 1=1" for d2 in depth2: globals() ['depth3_'+d2] = st.multiselect( f'{d2} 조건 설정할 필드 (복수 선택)', d2_options.get(d2) ) try: for d3 in globals() ['depth3_'+d2]: if d2=='날짜 범위': globals() ['depth4_date_'+d3] = st.date_input( f'{d3} 날짜 범위 선택', [datetime.date(datetime.now() - timedelta(days=30)), datetime.date(datetime.now())] ) try: start_date = datetime.strftime(globals() ['depth4_date_'+d3][0], '%Y-%m-%d') end_date = datetime.strftime(globals() ['depth4_date_'+d3][1], '%Y-%m-%d') where_sentence += f"\nand date({d3}) between date'{start_date}' and date'{end_date}'" if 'log' in depth1: start_pymd = datetime.strftime(globals() ['depth4_date_'+d3][0], '%Y%m%d') end_pymd = datetime.strftime(globals() ['depth4_date_'+d3][1], '%Y%m%d') where_sentence += f"\nand p_ymd between '{start_pymd}' and '{end_pymd}'" except: pass if d2=='숫자 범위': globals() ['depth4_num_'+d3] = st.text_input( f'{d3} 숫자 범위 입력 (x~y)' ) try: x = globals() ['depth4_num_'+d3].strip().split('~')[0] y = globals() ['depth4_num_'+d3].strip().split('~')[1] where_sentence += f"\nand {d3} between {x} and {y}" except: pass if d2=='특정 텍스트 포함': globals() ['depth4_text_include_'+d3] = st.text_input( f'{d3} 포함할 텍스트' ) globals() ['depth4_text_exclude_'+d3] = st.text_input( f'{d3} 제외할 텍스트' ) try: if globals() ['depth4_text_include_'+d3] != '': where_sentence += f"\nand {d3} like '%{globals() ['depth4_text_include_'+d3]}%'" except Exception as e: st.write(e) pass try: if globals() ['depth4_text_exclude_'+d3] != '': where_sentence += f"\nand {d3} not like '%{globals() ['depth4_text_exclude_'+d3]}%'" except Exception as e: st.write(e) pass if d2=='T/F': globals() ['depth4_bool_'+d3] = st.checkbox( f'{d3} 해당 여부' ) try: where_sentence += f"\nand {d3} = {globals() ['depth4_bool_'+d3]}" except: pass fin_query = f"""select * from {depth1} {where_sentence} limit 10""" except Exception as e: pass st.markdown('---') try: if fin_query: st.subheader("쿼리가 완성되었어요 (복사하세요!)") query = st.code( fin_query, language='sql' ) try: validation = pd.read_sql(fin_query.replace('%', '%%'), engine).head(5) st.write("정상 쿼리입니다.") st.markdown(""" <head> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> </head> <body> <a href="https://redash/queries/new" target = "_blank" class="btn btn-outline-primary" role="button">리대시에 쿼리 붙여넣기</a> </body> """, unsafe_allow_html=True) st.info(""" - 리대시에서 `limit 10`을 지우면 전체 결과를 조회하실 수 있습니다. """) # st.table(validation) except Exception as e: st.markdown(f"#### 비정상 쿼리입니다.\n```{e}```") except Exception as e: pass except: pass
위 코드를 요약하면 다음과 같습니다.
1. 도메인 선택
2. 테이블 선택
3. 쿼리 조건 선택
- 날짜 범위
- 숫자 범위
- 특정 텍스트 포함
- T/F (bool)
4. 선택한 조건 입력
5. 완성된 쿼리 활용
구현된 화면은 예상보다 단촐합니다^^;;
요점은, 데이터 마트를 도메인 별로 분류해서 각 도메인의 주요 테이블만 미리 정해 주면
나머지는 로직에 따라 모든 필드의 where절을 구성할 수 있다는 부분입니다.
쿼리를 어느 정도 쓰실 줄 아는 분들에게는 별 것 아니지만 where절을 구성하는 것도 어려운 분들께 최소한의 가이드를 잡아드리는 것을 목적으로 했습니다.
물론 이 기능을 사용하기 위해서는 테이블마다 각 필드가 무엇을 의미하는지 정보가 필요한데요,
저희는 이 부분을 datahub로 보완하고 있습니다.
다음 편에서는 유저 리스트를 추출할 수 있는 서비스와 실제 오픈 후 문제에 대해 회고하겠습니다.
'etc.' 카테고리의 다른 글
웹알못의 데이터 어드민 사이트 만들기(feat. Streamlit) 4. 보안을 보완 (1) 2022.09.10 웹알못의 데이터 어드민 사이트 만들기(feat. Streamlit) 3. 오픈은 실전 (1) 2022.09.10 웹알못의 데이터 어드민 사이트 만들기(feat. Streamlit) 1. 환경 구축 (0) 2022.09.10 웹알못의 데이터 어드민 사이트 만들기(feat. Streamlit) 0.Prologue (0) 2022.09.10 AWS EMR Prestosql(Trino) + Redash 업그레이드 (0) 2021.10.09