ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 데이터 중심 애플리케이션 설계 2장
    Data Engineering 2022. 2. 21. 17:58

    1. 데이터 모델

    - 다양한 유형의 데이터 모델이 있고 각 데이터 모델은 사용 방법에 대한 가정이 있다. 

      즉 어떤 동작은 쉽고 어떤 연산은 빠르고 다른 연산은 느리고, 어떤 데이터 변환은 자연스럽고 어떤 데이터 변환은 부자연스럽다.

    - 하나의 데이터 모델을 완전히 익히는 것도 어려운 일이다. 그러나 데이터 모델은 그 위에서 소프트웨어가 할 수 있는 일과 할 수 없는 일에 많은 영향을 주므로 애플리케이션에 적합한 데이터 모델을 선택하는 작업이 상당히 중요하다.

    - 관계형 데이터 모델, 문서 모델, 그래프 기반 데이터 모델(속성 그래프, 트리플 저장소 모델)을 2장에서 다룬다. 

     

    관계형 모델(SQL)

     - 관계(relation=sql에서 table)로 구성되고 각 관계는 순서없는 튜플(tuple, sql = row)의 모음

     

    비관계형 데이터 모델(NoSQL)

    - 임피던스 불일치(impedence mismatch) 해결을 위한 NoSQL 출현

      * 임피던스 불일치: 애플리케이션 코드와 데이터베이스 모델 객체(테이블,로우,컬럼)사이에 전환 계층이 필요한 경우

    - NoSQL 모델을 쓰면 불필요한 계층 변환 작업이 사라짐

     

     1 문서 모델

       - 애플리케이션이 주로 일대다 관계(트리 구조 데이터)거나 레코드간 관계가 없는 경우 적합

       - 데이터가 문서 자체에 포함돼 있으면서 하나의 문서와 다른 문서 간 관계가 거의 없는 경우  

     

     2 그래프형 데이터 모델

       - 다대다 관계가 매우 일반적일 경우 적합

     

     

    어떤 모델을 사용하는 것이 적합할까?

     - 예시: 관계형 스키마에서 이력서의 표현

      방법 1: 전통적인 SQL 모델을 사용, 

                정규화된 테이블을 만들기(상단 그림)

     

      방법 2: XML 데이터 지원이 추가된 SQL 데이터타입 사용,

                단일 로우에 다중 값을 저장하고 문서 내 질의와 색인이 가능해짐 

     

      방법 3: 직업,학력,연락처 정보를 json이나 xml 문서로 부호화하여 데이터베이스 텍스트 칼럼에 저장하고, 애플리케이션이 구조와 내용을 해석하게 함

                일반적으로 부호화된 칼럼의 값을 질의하는 데 데이터베이스를 사용할 수 없음

     

      방법 4: 문서 데이터베이스 사용(지역성 UP)

     

    {
         "user_id": 251,
         "first_name": "Bill",
         "last_name": "Gates",
         "summary": "Co-chair of the Bill & Melinda Gates... Active blogger.",
         "region_id": "us:91",
         "industry_id": 131,
         "photo_url": "/p/7/000/253/05b/308dd6e.jpg",
         "positions": [
             {"job_title": "Co-chair", "organization": "Bill & Melinda Gates Foundation"},
             {"job_title": "Co-founder, Chairman", "organization": "Microsoft"}
         ],
         "education": [
             {"school_name": "Harvard University", "start": 1973, "end": 1975},
             {"school_name": "Lakeside School, Seattle", "start": null, "end": null}
         ],
         "contact_info": {
             "blog": "http://thegatesnotes.com",
             "twitter": "http://twitter.com/BillGates"
         }
    }

                관계형 데이터베이스와 달리 조인 필요 X 질의 하나로 충분 

                

    문서 데이터베이스

     - 스키마리스(Schemaless)?

       정확히는 schema-on-read (반대말 schema-on-write)         

     

    스키마리스는 언제 강점을 가지는가? 

     - 예시: 하나의 필드에 사용자의 전체 이름 저장 --> 성과 이름을 분리하여 저장하도록 변경

     - schema on read의 경우: 간단함

    if (user && user.name && !user.first_name) {
         // Documents written before Dec 8, 2013 don't have first_name
         user.first_name = user.name.split(" ")[0];
    }

     - schema on write(rdbms)의 경우: migration 필요, 느리고 중단시간을 요구하여 좋지 않음

    ALTER TABLE users ADD COLUMN first_name text;
    UPDATE users SET first_name = split_part(name, ' ', 1); -- PostgreSQL
    UPDATE users SET first_name = substring_index(name, ' ', 1); -- MySQL

                

    2. 질의 언어

     

    명령형 언어

    • 보통의 프로그래밍 언어
    • 특정 순서로 특정 연산을 수행하도록 컴퓨터에 지시함. (방법)

    선언형 언어

    • SQL, (CSS, XSL : 문서의 스타일을 지정하기 위 한 선언형 언어 )
    • 알고자 하는 데이터의 패턴, 즉 결과가 충족해야 하는 조건과 데이터를 어떻게 변환(예를 들어 정렬, 그룹화, 집계) 할지를 지정 (목적)
    • 어떤 색인과 어떤 조인 함수를 사용할지, 질의의 다양한 부분을 어떤 순서로 실행할지(방법)를 결정하는 것은 데이터베이스 시스템의 질의 최적화기가 할 일이다.
    • 장점
      • 일반적으로 명령형 API보다 더 간결하고 쉽게 작업할 수 있음
      • 데이터베이스 엔진의 상세 구현이 숨겨져 있어 질의를 변경하지 않고도 데이터베이스 시스템의 성능을 향상시킬 수 있음 

    명령형 언어 vs 선언형 언어

     - 예시: 동물 목록에서 상어만 반환하기

     - 명령형 언어 (대부분의 프로그래밍 언어가 명령형 언어임)

    function getSharks() {
        var sharks = [];
        for (var i = 0; i < animals.length; i++) {
            if (animals[i].family === "Sharks") {
                sharks.push(animals[i]);
            }
        }
        return sharks;
    }

     - 선언형 언어

    SELECT * FROM animals WHERE family = 'Sharks';

     

    선언형, 명령형 질의

     - 선언형: DB, Web Browser에서 Good

     - 명령형: 문서형 DB에서 Good (절대적인것은 아님)

     

     - ex. CSS, XSL

     - ex. 다음 웹 문서에서

    <ul>
         <li class="selected">
             <p>Sharks</p>
             <ul>
                 <li>Great White Shark</li>
                 <li>Tiger Shark</li>
                 <li>Hammerhead Shark</li>
             </ul>
         </li>
         <li>
             <p>Whales</p>
             <ul>
                 <li>Blue Whale</li>
                 <li>Humpback Whale</li>
                 <li>Fin Whale</li>
             </ul>
         </li>
    </ul>

     - 선언형 질의 사용시(CSS) : 간단

    li.selected > p {
     background-color: blue;
    }

     - 명령형 질의 사용시 : 복잡

    var liElements = document.getElementsByTagName("li");
    for (var i = 0; i < liElements.length; i++) {
      if (liElements[i].className === "selected") {
        var children = liElements[i].childNodes;
        for (var j = 0; j < children.length; j++) {
          var child = children[j];
          if (child.nodeType === Node.ELEMENT_NODE && child.tagName === "P") {
            child.setAttribute("style", "background-color: blue");
          }
        }
      }
    }

     

    맵리듀스 질의

    * postgre sql : 선언형

    SELECT date_trunc('month', observation_timestamp) AS observation_month,
                  sum(num_animals) AS total_animals
    FROM observations
    WHERE family = 'Sharks'
    GROUP BY observation_month;

     

     

    * MongoDB 맵리듀스 기능

    db.observations.mapReduce(
        function map() {
          var year = this.observationTimestamp.getFullYear();
          var month = this.observationTimestamp.getMonth() + 1;
          emit(year + "-" + month, this.numAnimals);
        },
        function reduce(key, values) {
          return Array.sum(values);
        },
        {
          query: { family: "Sharks" },
          out: "monthlySharkReport"
        }
    );

    * 데이터 예시(문서 2개)

    {
    
        observationTimestamp: Date.parse("Mon, 25 Dec 1995 12:34:56 GMT"),
    
        family: "Sharks",
    
        species: "Carcharodon carcharias",
    
        numAnimals: 3
    
    }
    
    {
    
        observationTimestamp: Date.parse("Tue, 12 Dec 1995 16:17:18 GMT"),
    
        family: "Sharks",
    
        species: "Carcharias taurus",
    
        numAnimals: 4
    
    }

     

    * 맵리듀스 질의 결과

     emit("1995-12", 3)

     emit("1995-12", 4)

     => reduce("1995-12", [3,4])

     

     => return 7 (monthlySharkReport)

     

    * 몽고 DB에서 지원하는 집계파이프라인 (선언형 질의)

    db.observations.aggregate([
        { $match: { family: "Sharks" } },
        { $group: {
            _id: {
                year: { $year: "$observationTimestamp" }, 
                month: { $month: "$observationTimestamp" }
        },
            totalAnimals: { $sum: "$numAnimals" }
        } }
    ]);

     -> 분산환경이라고 꼭 맵리듀스를 사용하는 건 아님

     -> map, reduce 함수 선정이 어려워서 몽고DB에서 집계 파이프라인 제공하고 있음. (질의 최적화기가 질의 성능을 높임)

     

    3. 그래프형 데이터 모델 

    속성 그래프

     

    사이퍼 질의 언어 : 속성 그래프에 적합

    데이터 생성

    CREATE
        (NAmerica:Location {name:'North America', type:'continent'}),
        (USA:Location {name:'United States', type:'country' }),
        (Idaho:Location {name:'Idaho', type:'state' }),
        (Lucy:Person {name:'Lucy' }),
        (Idaho) -[:WITHIN]-> (USA) -[:WITHIN]-> (NAmerica),
        (Lucy) -[:BORN_IN]-> (Idaho)

    질의: 미국에서 유럽으로 이민 온 사람의 이름을 질의 

    MATCH
        (person) -[:BORN_IN]-> () -[:WITHIN*0..]-> (us:Location {name:'United States'}),
        (person) -[:LIVES_IN]-> () -[:WITHIN*0..]-> (eu:Location {name:'Europe'})
    RETURN person.name

    관계형 스키마를 사용해 속성 그래프 표현하기

    CREATE TABLE vertices (
        vertex_id integer PRIMARY KEY,
        properties json
    );
    CREATE TABLE edges (
        edge_id integer PRIMARY KEY,
        tail_vertex integer REFERENCES vertices (vertex_id),
        head_vertex integer REFERENCES vertices (vertex_id),
        label text,
        properties json
    );
    CREATE INDEX edges_tails ON edges (tail_vertex);
    CREATE INDEX edges_heads ON edges (head_vertex);

    SQL로 속성 그래프 질의 : with recursive - 복잡도 UP

    WITH RECURSIVE
        -- in_usa is the set of vertex IDs of all locations within the United States
        in_usa(vertex_id) AS (
            SELECT vertex_id FROM vertices WHERE properties->>'name' = 'United States'
            UNION
            SELECT edges.tail_vertex FROM edges
            JOIN in_usa ON edges.head_vertex = in_usa.vertex_id
            WHERE edges.label = 'within'
            ), 
        -- in_europe is the set of vertex IDs of all locations within Europe
        in_europe(vertex_id) AS (
            SELECT vertex_id FROM vertices WHERE properties->>'name' = 'Europe'
            UNION
            SELECT edges.tail_vertex FROM edges
            JOIN in_europe ON edges.head_vertex = in_europe.vertex_id
            WHERE edges.label = 'within'
        ),
        -- born_in_usa is the set of vertex IDs of all people born in the US
        born_in_usa(vertex_id) AS (
            SELECT edges.tail_vertex FROM edges
            JOIN in_usa ON edges.head_vertex = in_usa.vertex_id
            WHERE edges.label = 'born_in'
        ),
        -- lives_in_europe is the set of vertex IDs of all people living in Europe
        lives_in_europe(vertex_id) AS (
            SELECT edges.tail_vertex FROM edges
            JOIN in_europe ON edges.head_vertex = in_europe.vertex_id
            WHERE edges.label = 'lives_in'
        )
    SELECT vertices.properties->>'name'
    FROM vertices
    -- join to find those people who were both born in the US *and* live in Europe
    JOIN born_in_usa ON vertices.vertex_id = born_in_usa.vertex_id
    JOIN lives_in_europe ON vertices.vertex_id = lives_in_europe.vertex_id;

     

    트리플 저장소 모델

    (주어, 서술어, 목적어) 형식으로 저장함

    - 터틀 형식으로 데이터 표현시

    @prefix : <urn:example:>.
    _:lucy a :Person; :name "Lucy"; :bornIn _:idaho.
    _:idaho a :Location; :name "Idaho"; :type "state"; :within _:usa.
    _:usa a :Location; :name "United States"; :type "country"; :within _:namerica.
    _:namerica a :Location; :name "North America"; :type "continent".

    스파클 질의 언어

     - RDF(Resource Description Framework. 자원 기술 프레임워크) 데이터 모델을 사용한 트리플 저장소 질의 언어 

     - 사이퍼와 구조가 매우 유사함

     

     

     

     

     

     

     

    'Data Engineering' 카테고리의 다른 글

    Oracle Statistics  (0) 2023.11.14
    Git Bash로 AWS 접속하기  (0) 2023.04.07
    git  (0) 2022.02.16
    Druid  (0) 2022.02.08
    elastic search  (0) 2022.02.08

    댓글

Designed by Tistory.