한눈에 살펴보는 PostgreSQL


NHN에서는 CUBRID라는 오픈소스 DBMS를 개발하고 있으며 사내외 여러 서비스에 적용해 안정적으로 운영하고 있습니다. 여기서 살펴볼 PostgreSQL도 오픈소스 DBMS며, 여러 나라의 다양한 개발자들의 자발적인 노력으로 개발되고 있습니다. 오픈소스 프로젝트로는 상당히 긴 역사인 15년 이상의 오랜 역사를 가지고 있고 최근에는 1년 여만에 새로운 버전인 9.2 버전을 출시했습니다. 이 글에서는 꾸준히 발전해 가는 PostgreSQL가 어떤 데이터베이스인지 알아보겠습니다.

PostgreSQL을 알아야 할 이유

PostgreSQL(http://www.postgresql.org) 은 북미와 일본에서는 높은 인지도와 많은 인기를 얻고 있는 RDBMS다. 국내에서는 아직 잘 사용하지 않고 있지만, 기능과 성능면에서 매우 훌륭한 RDBMS이기 때문에 PostgreSQL가 어떠한 데이터베이스인지 시간을 들여 알아볼 필요는 있다.

PostgreSQL(포스트-그레스-큐엘 [Post-Gres-Q-L]로 발음)은 객체-관계형 데이터베이스 시스템(ORDBMS)으로, 엔터프라이즈급 DBMS의 기능과 차세대 DBMS에서나 볼 수 있을 법한 많은 기능을 제공하는 오픈소스 DBMS다. 실제 기능적인 면에서는 Oracle과 유사한 것이 많아, Oracle 사용자들이 가장 쉽게 적응할 수 있는 오픈소스 DBMS가 PostgreSQL이라는 세간의 평 또한 많다.

역사

PostgreSQL의 조상에는 여러 제품이 있는데, 그중 Ingres(INteractive Graphics REtrieval System)는 PostgreSQL의 시조라고 할 수 있다. 이 Ingres는 현재까지도 활발하게 활동하고 있는 데이터베이스 계의 거장 Michael Stonebraker가 시작한 프로젝트다.

postgresql1

그림 1 Michael Stonebraker(원본 출처: https://www.facebook.com/michael.stonebraker)

이 Ingres는 1977년 미국 버클리대학에서 시작한 프로젝트다. 이후 Ingres를 잇는 Postgres(Post-Ingres)라는 또 다른 프로젝트 또한 그의 손을 거쳐 탄생됐다. 1991년 Postgres 버전 3이 출시되면서 많은 사용자를 확보했으나 사용자 지원에 대한 부담이 증가해 결국 프로젝트는 1993년에 종료됐다. 이후에도 Postgres는 현재의 Informix 제품에 상당 부분 영향을 준 것으로 알려져 있다(Postgres를 상용화한 Illustra는 1997년 Informix에 인수됐고 2001년에 Illustra는 IBM에 인수됐다).

postgresql2

그림 2 제품 변천사

하지만 Postgres 사용자와 학생들이 프로젝트 종료 선언과 별개로 Postgres의 개발을 계속 진행했고, SQL 지원과 구조 개선을 통해 Postgres보다 40% 정도 빠른 성능을 보여 주는 Postgres95를 만들어 냈다.

이 Postgre95는 1996년 오픈소스가 되면서 Postgres를 계승했다는 것과 SQL을 지원한다(Postgres는 SQL이 아니라 QUEL이라는 언어를 지원했다)는 것을 반영하기 위해 현재의 PostgreSQL로 이름을 변경한 후 1997년 최초 버전을 6.0으로 정해 PostgreSQL을 출시했다.

이후에도 PostgreSQL은 오픈 소스 커뮤니티에 의해 최근까지도 활발히 개발되고 있으며 2012년 10월 현재 9.2 버전까지 출시됐다.

또한 개방된 라이선스(BSD나 MIT 라이선스와 비슷하게 상용적인 사용과 수정을 허용하며 단, 사용 중 발생하는 문제에 대해 법적 책임이 없음을 명확히 함)의 특징으로 인해 20종 이상의 다양한 분기(fork)가 존재했으며, 그중 많은 수가 PostgreSQL에 다시 영향을 주거나 혹은 사라졌다.

PostgreSQL의 로고는 'Slonik'이라는 이름을 가진 코끼리다. 코끼리를 로고로 사용하게 된 정확한 근원은 찾을 수 없으나 과거의 흔적을 뒤져 보면, 오픈소스화된 직후 한 사용자가 아가사 크리스티의 소설 '코끼리는 기억한다'에서 착안해 제안한 것으로 보인다. 이후 모든 공식적인 자리에서 이 코끼리 로고는 빠지지 않고 등장하게 됐다. 코끼리는 크고 강하고 믿음직하며 기억력이 좋다는 이미지 때문에 Hadoop이나 Evernote도 코끼리를 공식 로고로 사용하고 있다.

postgresql3

그림 3 PostgreSQL의 로고*

기능 및 제한

PostgreSQL은 관계형 DBMS의 기본적인 기능인 트랜잭션과 ACID(Atomicity, Consistency, Isolation, Durability)를 지원한다. 또한 ANSI SQL:2008 규격을 상당 부분 만족시키고 있으며, 전부를 지원하는 것을 목표로 현재도 기능이 계속 추가되고 있다.

또한 PostgreSQL은 기본적인 신뢰도와 안정성을 위한 기능뿐만 아니라 진보적인 기능이나 학술적 연구를 위한 확장 기능도 많이 가지고 있다. PostgreSQL의 기능을 대략적으로 열거해 보더라도 상당히 많은 기능을 가지고 있음을 알게 된다.

  • Nested transactions (savepoints)
  • Point in time recovery
  • Online/hot backups, Parallel restore
  • Rules system (query rewrite system)
  • B-tree, R-tree, hash, GiST method indexes
  • Multi-Version Concurrency Control (MVCC)
  • Tablespaces
  • Procedural Language
  • Information Schema
  • I18N, L10N
  • Database & Column level collation
  • Array, XML, UUID type
  • Auto-increment (sequences),
  • Asynchronous replication
  • LIMIT/OFFSET
  • Full text search
  • SSL, IPv6
  • Key/Value storage
  • Table inheritance

이외에도 엔터프라이즈급 DBMS의 다양한 기능과 새로운 기능을 자랑하고 있다.

PostgreSQL의 일반적인 제한 사항은 아래와 같다.

표 1 기본 제한 사항

항목제한 사항
최대 DB 크기(Database Size)무제한
최대 테이블 크기(Table Size)32TB
최대 레코드 크기(Row Size)1.6TB
최대 컬럼 크기(Field Size)1 GB
테이블당 최대 레코드 개수(Rows per Table)무제한
테이블당 최대 컬럼 개수(Columns per Table)250~1600개
테이블당 최대 인덱스 개수(Indexes per Table)무제한

로드맵

2012년 10월 기준 최신 버전은 9.2이다. PostgreSQL의 발전 과정을 연도별로 간단히 정리하면 <그림 4>와 같이 나타낼 수 있을 것이다.

postgresql4

그림 4 연도별 발전 과정(원본 출처: http://momjian.us/main/writings/pgsql/features.pdf)

버전별 주요 기능은 다음과 같다.

표 2 버전별 주요기능

버전출시주요 기능
0.011995Postgres95 릴리스
1.01995저작권 변경, 오픈소스화
6.0 ~ 6.51997 ~ 1999PostgreSQL로 이름 변경 Index, VIEWs and RULEs Sequences, Triggers Genetic Query Optimizer Constraints, Subselect MVCC, JDBC interface,
7.0 ~ 7.42000 ~ 2010Foreign keys SQL92 syntax JOINs Write-Ahead Log Information Schema, Internationalization
8.0 ~ 8.42005 ~ 2012Microsoft Windows Native 버전 지원 Savepoint, Point-in-time recovery Two-phase commit Table spaces, Partitioning Full text search Common table expressions (CTE) SQL/XML, ENUM, UUID Type Window functions Per-database collation 복제, Warm standby
9.02010-09Streaming 복제, Hot standby Microsoft Windows 64bit 버전 지원 Per-column conditional trigger
9.12011-09기능 차별화 Synchronous 복제 Per-column collations Unlogged tables K-nearest-neighbor indexing Serializable isolation level Writeable CTE (WITH) SQL/MED External Data SE-Linux integration
9.22012-09성능 최적화 linear scalability to 64 cores CPU 전력 소비량 감소 Cascade streaming 복제 JSON, Range Type Lock management 개선 Space-partitioned GiST index Index-only scans (covering)

이후 PostgreSQL 9.3 버전은 2013년 3분기 출시를 목표로 현재 개발이 진행 중이며, 주요 기능으로는 관리 기능 개선, Parallel query 지원, MERGE/UPSERT 지원, Multi-Master 복제, Materialized View 기능, 다중 언어 지원 개선 등이 계획되어 있다. 더 자세한 내용은 http://wiki.postgresql.org/wiki/Todo 에서 살펴볼 수 있다.

내부 구조

PostgreSQL의 프로세스 구조를 간단히 살펴보면 다음과 같다.

postgresql5

그림 5 프로세스 구조

클라이언트는 인터페이스 라이브러리(libpg, JDBC, ODBC 등의 다양한 인터페이스)를 통해 서버와의 연결을 요청(1)하면, Postmaster 프로세스가 서버와의 연결을 중계(2)한다. 이후 클라이언트는 할당된 서버와의 연결을 통해 질의를 수행(3)한다(그림 5).

서버 내부의 질의 수행 과정을 간단히 살펴보면 다음과 같다.

postgresql6

그림 6 쿼리 수행 절차

클라이언트로부터 질의 요청이 들어오면 구문 분석 과정(1)을 통해 Parse Tree를 생성하고 의미 분석 과정(2)를 통해 새로운 트랜잭션을 시작하고 Query Tree를 생성한다.

이후 서버에 정의된 Rule에 따라 Query Tree가 재 생성(3)되고 실행 가능한 여러 수행 계획 중 가장 최적화된 Plan Tree를 생성(4)한다. 서버는 이를 수행(5)하여 요청된 질의에 대한 결과를 클라이언트로 전달하게 된다(그림 6).

서버의 쿼리 수행 과정에서는 데이터베이스 내부의 시스템 카탈로그가 많이 사용되는데, 사용자가 함수나 데이터 타입은 물론 인덱스 접근 방식 및 RULE 등을 시스템 카탈로그에 직접 정의할 수도 있다. 따라서 PostgreSQL에서는 이것이 기능을 새로 추가하거나 확장하는데 있어 중요한 포인트로 활용된다.

데이터가 저장되는 파일들은 여러 개의 페이지들로 구성되며, 하나의 페이지는 확장 가능한 slotted page 구조를 가진다(그림 7, 그림 8).

postgresql7

그림 7 데이터 페이지 구조

postgresql8

그림 8 인덱스 페이지 구조

개발 프로세스

PostgreSQL의 개발 프로세스 모델은 다음의 문장으로 설명할 수 있다.

"소수 주도의 커뮤니티 기반 오픈 소스 프로젝트"

이는 Linux, Apache, Eclipse 프로젝트와 같이 소수의 관리자와 다양한 개발자 그리고 다수의 사용자가 프로젝트 구성원을 이루고 있으며, 소수의 관리자 그룹(Core Team)은 다수의 사용자로부터의 요청과 피드백을 수집(우선순위를 정하기 위해 투표 방식을 활용하기도 한다. 자세한 내용은 http://postgresql.uservoice.com 를 참조한다.)하여 제품의 방향을 결정하고 코드의 최종 승인 및 릴리스 권한을 행사한다(MySQL 또는 JBoss와 같은 기업 관리형 개발프로세스와는 다른 모델로 분류됨).

개발자 그룹은 코드 커미터, 코드 개발자/기여자로 구성되어 있으며 이들은 미국, 일본, 유럽 등의 여러 나라에 분포되어 있다.

다양한 개발자들에 의해 개발된 코드는 다양한 리뷰 과정(Submission Review, Usability Review, Feature Test, Performance Review, Coding Review, Architecture Review, Review Review)과 Core Team의 승인을 거처 제품에 반영이 된다. 커뮤니티에서는 오래 전부터 사용해오던 메일링 리스트가 주로 사용되고 있으며, 매뉴얼을 포함한 다양한 문서들이 공식 홈페이지(http://www.postgresql.org) 에서 잘 관리되고 있다.

경쟁 제품

PostgreSQL은 엔터프라이즈급 상용 데이터베이스와 비교되기를 원하나 주로 유명 오픈소스 DBMS가 비교 대상이 된다. 오픈소스 DBMS의 캐치프레이즈로 제품 특징만을 나열해 보면 다음과 같다.

  • PostgreSQL: The world's most advanced open source database
  • MySQL: The world's most popular open source database
  • Firebird: The true open source database
  • CUBRID: Open Source Database Highly Optimized for Web Applications
  • SQLite: self-contained library, serverless, zero-configuration, transactional SQL database engine

캐치프레이즈만으로 제품을 비교하긴 어려우나 PostgreSQL은 진보와 개방을 표방하고 있음을 알 수 있다.

다음은 PostgreSQL이 경쟁 제품으로 내세우는 제품에 대한 간략한 비교다.

표 3 경쟁 제품 비교

Oracle오랫동안 검증된 방대한 양의 코드, 다양한 레퍼런스. 그러나 비싼 비용이 단점
DB2, MS SQLOracle과 비슷함
MySQL다양한 응용과 레퍼런스. 그러나 기업형 개발 모델과 라이선스 부담
다른 상용 DB오픈소스 DBMS에 의해 세력이 기우는 중
타 오픈소스DB프로젝트에 개발자를 끌어 들이기 위해 힘든 노력 중

이전부터 PostgreSQL 진영은 엔터프라이즈 시장에 진출하려는 시도를 계속 해 왔고, 2004년에는 PostgreSQL을 이용한 전문 기업인 EnterpriseDB(http://www.enterprisedb.com) 가 생겨나 엔터프라이즈 DBMS 시장을 좀 더 확고히 다지기 위한 노력을 기울이고 있다. 대표적인 산출물이 Postgres Plus Advanced Server 제품의 출시다. 이는 오픈 소스 PostgreSQL에 Oracle 호환성 기능(PL/SQL, SQL 구문, 함수, DB Links, OCI 라이브러리 등 지원)과 관리 도구를 추가해 용이한 데이터 및 응용 마이그레이션과 Oracle 대비 20% 이하의 비용 절감을 주무기로 내세우고 있다(그림 10).

postgresql9

그림 10 Oracle 대비 비용 절감 효과(원본 출처)

또한 PostgreSQL 전문가의 교육, 컨설팅, 마이그레이션 및 기술 지원 서비스 등을 제공하는 등의 차별화된 서비스도 제공하며 각종 분야 약 300여 개의 레퍼런스 사이트를 통해 모든 업계에서 사용 가능한 데이터베이스임을 홍보하며 세계 각지에 사용자 층을 늘리고 있는 추세다.

현황, 동향

대부분의 PostgreSQL 사용기를 읽어 보면 알 수 있듯이 PostgreSQL을 사용하는 사람들은 대부분 개발자적인 성향을 가지고 있으며 제품에 대한 애정도와 충성도가 높은 편이다.

그도 그럴 것이 다른 제품과 비교하면 일반적으로 부족하지 않은 기능과 무난한 성능을 가지고 있고, 또 하나 중요한 것은 새로운 개발자를 끌어 들이기에 좋은 입문 조건들을 가지고 있다는 것이다.

프로젝트 페이지에 잘 정리된 매뉴얼, 문서와 300종 이상의 관련 서적, 그리고 세계 각국에서 개최되는 매년 10회 이상의 다양한 세미나와 콘퍼런스 등도 이를 뒷받침하고 있으며 최근에는 전문 잡지까지 등장했다. 이는 모두 왕성한 커뮤니티 활동의 산물이라 할 수 있다.

사용자가 꼽는 PostgreSQL의 대표적인 특징으로는 다음과 같은 것들이 있다.

  • '신뢰도'는 제품의 최우선 사항
  • ACID 및 트랜잭션 지원
  • 다양한 인덱싱 기법 지원
  • 유연한 Full-text search 기능
  • 동시성 성능을 높여주는 MVCC 기능
  • 다양하고 유연한 복제 방식 지원
  • 다양한 프로시져(PL/pgSQL, Perl, Python, Ruby, TCL, 등)/인터페이스(JDBC, ODBC, C/C++, .Net, Perl, Python, 등) 언어
  • 질 좋은 커뮤니티 지원 및 상업적인 지원
  • 잘 만든 문서 및 충분한 매뉴얼 제공

그리고, 다양한 확장 기능과 확장 기능 개발의 용이성 등이 있으며 PostgreSQL만의 차별화된 확장 기능으로 다음과 같은 것들이 있다.

  • GIS add-on 지원 (PostGIS)
  • Key-Value 스토어 확장 기능 (HStore)
  • DBLink 기능
  • Crypto, UUID 등 다양한 함수, 타입 지원

이외에도 실용적이거나 실험적인 많은 확장 기능들이 있다.

이중 최근 들어 많이 회자되는 GIS(Geographic Information System) 기능에 대해 간략히 살펴보자. PostGIS(http://postgis.refractions.net) 는 PostgreSQL에 OpenGIS 규격(http://www.opengeospatial.org/standards/sfs) 을 준수하며 Geographic object를 지원 가능하게 하는 미들웨어 형태의 확장 기능이다(그림 11). 2001년부터 개발됐으며 많은 기능과 성능 개선을 통해 오픈 소스로는 가장 많은 사용자를 확보하고 있다. 상용 제품으로는 Oracle Spatial, DB2, MS SQL Server 등도 있으나 비용 대 성능 측면에서 상용 제품은 그다지 환영 받지 못하고 있다.

게다가 PostGIS/PostgreSQL의 제공 기능이나 성능은 Oracle과 비견할만하다는 벤치마크 자료를 어렵지 않게 구할 수 있다.

postgresql10

그림 11 PostGIS 구조

그리고 최근 동향을 살펴보면 GIS 분야 외에도 클라우드와 관련해서도 PostgreSQL가 많이 회자되고 있다. 최근 DbaaS(DB As A Service)를 제공하는 기업이 늘어나면서 비용과 라이선스 측면에서 유리한 PostgreSQL에 대한 수요가 증가했고 EnterpriseDB 사는 이에 맞추어 클라우드 시장을 겨냥하여 다음의 특징을 갖는 Postgres Plus Cloud Database 제품을 출시했다.

  • Simple setup & web-based management
  • Automatic scaling, load balancing and failover
  • Automated online backup
  • Database Cloning

이는 Amazon EC2, Eucalyptus cloud, Red Hat Openshift development platform cloud 등에서 사용되며 다른 Heroku, dotCloud 등의 많은 클라우드 서비스 업체에서도 PostgreSQL을 사용하는 서비스를 제공하고 있다.

마치며

MySQL을 인수했던 Sun이 2009년 Oracle에 인수되면서 좀더 폐쇄적인 기업형 프로젝트 성향을 보이고 비슷한 시기에 많은 수의 MySQL 개발자들이 떠나게 되자 이를 불안해 하는 MySQL 사용자들은 손쉽게 이전할 수 있는 MySQL의 fork(MariaDB, Drizzle, Percona 등)뿐만 아니라 20년 이상 잘 지속되어 개발되고 있는 PostgreSQL으로의 이전에도 신경을 쓰고 있는 듯 하다.

미국의 유명한 취업 포털 회사인 indeed(http://www.indeed.com) 의 PostgreSQL과 MySQL 관련 업무에 대한 구인 증가율 추이(그림 9)를 보면, 2011년 들어서는 MySQL의 구인 증가율이 한풀 꺾인 듯 보이나 PostgreSQL 업무 구인은 꾸준히 증가하고 있는 것으로 보인다.

postgresql11

그림 12 indeed의 구인 증가율 추이(원본 출처)

검색 사이트에서의 검색 빈도를 보면 MySQL의 추세가 지속적으로 줄어들고 있고 전체적으로 PostgreSQL의 추이는 거의 변동이 없는 것으로 보이나 국내에서는 2010년 중반 이후 지속적인 증가 추세를 보이고 있다.

물론 아직까지도 PostgreSQL 보다는 MySQL의 인기도나 사용률이 월등히 높은 편이다. 이런 추이들로 정확한 현황이나 향후 추세를 알 수는 없겠지만 대략적으로는 MySQL의 인기도가 하락하면 PostgreSQL의 인기도가 상승할 것이라고 짐작할 수는 있을 것이다.

아직은 MySQL의 인기도를 꺾을 파괴력을 지니지는 않았으나, 이를 대비하여 PostgreSQL 오픈 소스 프로젝트 진영에서는 다음과 같은 노력을 지속적으로 하고 있으며

  • 기본적인 DBMS 기능의 신뢰도 증대
  • 진보적이며 차별화된 기능 확장
  • 오픈 소스 개발자의 지속적 확충

또한 비지니스의 목적이 강한 EnterpriseDB 진영에서는 다음과 같은 행보가 지속적으로 이루어 지고 있다.

  • 엔터프라이즈 시장에서의 영역 확대
  • 클라우드 시장에서의 영역 확대
  • Oracle 및 MySQL을 대체하기 위한 노력


Button클릭 시 image/* 파일들 선택할 수 있는 창 열기

<요약>

OnCreate 부문에 Button onClickListener을 추가 하고, Intent를 활용하여 

전체적인 파일을 가져올 수 있게 합니다.

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Button openimg = (Button)findViewById(R.id.openimg);
openimg.setOnClickListener(new Button.OnClickListener(){
public void onClick(View view){
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivity(intent);
}
});

}


때때로 Android애플리케이션에서 사용자가 선택한 후에 응용 프로그램에 의해 표시되는 갤러리에서 이미지를 선택할 수 있는 갤러리에서 이미지를 선택할 수 있습니다.

이 글에서는 사용자가 모든 앱에서 이미지를 선택할 수 있는 단일 인터페이스를 호출하는 방법을 살펴보겠습니다.(예:갤러리, 사진, ESFileExplorer등)및 폴더(GoogleDrive, 최근, 다운로드 등)를 인첸트를 사용합니다.



갤러리 이미지 갤러리 시작


사용자가 다음과 같은 의도로 다음과 같은 의도를 사용할 수 있도록 하려면 사용자가 이미지를 선택할 수 있습니다.

Intent intent = new Intent();
// Show only images, no videos or anything else
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
// Always show the chooser (if there are multiple options available)
startActivityForResult(Intent.createChooser(intent, "Select Picture"), PICK_IMAGE_REQUEST);


PICK_IMAGE_REQUEST는 인스턴스 변수로 정의된 요청 코드입니다.

private int PICK_IMAGE_REQUEST = 1;


Activity/Fragment에서 선택한 영상 표시

일단 선택이 이루어지면 ImageView 사용자 인터페이스에서 이미지를 플립 차트에 표시합니다.

이를 위해서는 onActivityResult()를 오버 라이드 해야 합니다.


@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
 
    if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) {
 
        Uri uri = data.getData();
 
        try {
            Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
            // Log.d(TAG, String.valueOf(bitmap));
 
            ImageView imageView = (ImageView) findViewById(R.id.imageView);
            imageView.setImageBitmap(bitmap);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

이렇게 배치하려면 다음과 같은 작업을 수행해야 합니다.

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/imageView" />


갤러리에서 선택할 때 선택한 사진이 UI에 표시되고 선택한 사진이 어떻게 표시되는지 확인할 수 있습니다.


컨텐츠 URI에서 절대 파일 경로 가져오기


Uri uri = data.getData();
String[] projection = { MediaStore.Images.Media.DATA };
 
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
cursor.moveToFirst();
 
Log.d(TAG, DatabaseUtils.dumpCursorToString(cursor));
 
int columnIndex = cursor.getColumnIndex(projection[0]);
String picturePath = cursor.getString(columnIndex); // returns null
cursor.close();


그러면 커서에서 반환된 MediaStore.Images.Media.DATA 값이 null이라는 것을 알 수 있습니다.

이 문제(및 수정 사항)는 다음과 같은 스레드 스레드에서 해결되었습니다.


Button클릭 시 image/* 파일들 선택할 수 있는 창 열기

<요약>

OnCreate 부문에 Button onClickListener을 추가 하고, Intent를 활용하여 

전체적인 파일을 가져올 수 있게 합니다.

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Button openimg = (Button)findViewById(R.id.openimg);
openimg.setOnClickListener(new Button.OnClickListener(){
public void onClick(View view){
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivity(intent);
}
});

}


때때로 Android애플리케이션에서 사용자가 선택한 후에 응용 프로그램에 의해 표시되는 갤러리에서 이미지를 선택할 수 있는 갤러리에서 이미지를 선택할 수 있습니다.

이 글에서는 사용자가 모든 앱에서 이미지를 선택할 수 있는 단일 인터페이스를 호출하는 방법을 살펴보겠습니다.(예:갤러리, 사진, ESFileExplorer등)및 폴더(GoogleDrive, 최근, 다운로드 등)를 인첸트를 사용합니다.



갤러리 이미지 갤러리 시작


사용자가 다음과 같은 의도로 다음과 같은 의도를 사용할 수 있도록 하려면 사용자가 이미지를 선택할 수 있습니다.

Intent intent = new Intent();
// Show only images, no videos or anything else
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
// Always show the chooser (if there are multiple options available)
startActivityForResult(Intent.createChooser(intent, "Select Picture"), PICK_IMAGE_REQUEST);


PICK_IMAGE_REQUEST는 인스턴스 변수로 정의된 요청 코드입니다.

private int PICK_IMAGE_REQUEST = 1;


Activity/Fragment에서 선택한 영상 표시

일단 선택이 이루어지면 ImageView 사용자 인터페이스에서 이미지를 플립 차트에 표시합니다.

이를 위해서는 onActivityResult()를 오버 라이드 해야 합니다.


@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
 
    if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) {
 
        Uri uri = data.getData();
 
        try {
            Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
            // Log.d(TAG, String.valueOf(bitmap));
 
            ImageView imageView = (ImageView) findViewById(R.id.imageView);
            imageView.setImageBitmap(bitmap);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

이렇게 배치하려면 다음과 같은 작업을 수행해야 합니다.

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/imageView" />


갤러리에서 선택할 때 선택한 사진이 UI에 표시되고 선택한 사진이 어떻게 표시되는지 확인할 수 있습니다.


컨텐츠 URI에서 절대 파일 경로 가져오기


Uri uri = data.getData();
String[] projection = { MediaStore.Images.Media.DATA };
 
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
cursor.moveToFirst();
 
Log.d(TAG, DatabaseUtils.dumpCursorToString(cursor));
 
int columnIndex = cursor.getColumnIndex(projection[0]);
String picturePath = cursor.getString(columnIndex); // returns null
cursor.close();


그러면 커서에서 반환된 MediaStore.Images.Media.DATA 값이 null이라는 것을 알 수 있습니다.

이 문제(및 수정 사항)는 다음과 같은 스레드 스레드에서 해결되었습니다.

요청에 의해 호출된 앱에서 다양한 섹션(탐색 드로어에 있는)을 선택할 때마다 다양한 종류의 Content URIs가 반환됩니다.

갤러리(앱)섹션의 선택 항목에서 얻을 수 있는 것은 다음과 같습니다.

Recents(또는 일반적으로 내 생각)에서는 다음과 같은 이점을 얻을 수 있습니다.

GoogleDrive에서 선택할 때는 다음과 같은 URI를 사용합니다.

또한 사진(앱)섹션에서 다음을 수행합니다(URL인코딩됨).





버튼 위치 내가 원하는 곳에 설정하기

처음 만들면 스튜디오 안에서는 정상작동하나, 핸드폰을 활용할 시 error문구와 함꼐 0,0으로 이동이 됩니다.

<Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        tools:layout_editor_absoluteX="62dp"
        tools:layout_editor_absoluteY="310dp" />


이 구문을 

<Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.291" />

와 같이 설정하고, 디자인 부분에서 위치를 조절해준다면 원하는 위치에 배열할 수 있습니다.





Q

사람들이 'public static final String mystring = ~~~' 을 작성한 다음 많은 값을 사용하는 코드를 보았습니다.


왜 그들은 그것을해야하나요? 왜 그들은 그것을 사용하기 전에 최종 값으로 초기화해야합니까?

그 핵심 (public static final)의 의미를 이해합니다.

내가 이해하지 못하는 것은 상수가 

한 곳에서만 사용되고 같은 클래스에서만 사용 되더라도 사람들이 왜 그것을 사용하는지에 대한 것입니다. 

그것을 선언하는 이유는 무엇입니까? 왜 우리는 변수를 사용하지 않습니까?


A

final은 변수의 값이 변경되지 않음을 나타냅니다. 즉, 값을 선언 한 변수는 선언 된 후에 수정할 수 없습니다.


public final static String 을 사용하면 다음과 같은 String을 만들 수 있습니다.

1. 클래스 (static : 그것을 사용하는 데 필요한 인스턴스가 없음)에 속하며,

2. 클래스의 모든 인스턴스와 클래스를 사용하는 다른 객체에서 사용할 수있는
   String 상수를 정의하려는 경우와 같이 변경되지 않습니다 (final).


ex)

public final static String MY_CONSTANT = "SomeValue";

// ... 다른 코드에서 다른 객체에 상수를 사용합니다.
if (input.equals(MyClass.MY_CONSTANT)

비슷하게

public static final int ERROR_CODE = 127;


즉,

final을 사용할 필요는 없지만 프로그램 실행 중에 실수로 변경되는 상수를 유지하고 변수가

상수라는 표시기로 사용됩니다.


final 상수가 현재 클래스 및 또는 한 곳에서만 사용되는 경우에도 모든 상수를 최종으로 선언하는 것이 좋습니다.

final : 코드의 수명이 다할 때까지 상수가 여러 곳에서 사용될 수 있습니다.

또한 final을 사용하면 구현시 일부 최적화를 수행 할 수 있습니다.




+ 다른 답변 해석

static 이란 클래스를 인스턴스화하거나 객체를 사용하지 않고도 사용할 수 있습니다.

final은 문자열 상수를 만드는데 사용되는 키워드입니다. 해당 문자열의 값은 변경할 수 없습니다.

 아래 예를보세요.

  public class StringTest { 
           static final String str = "Hello"; 
  public static void main(String args[]) { 
           // str = "world"; // 주석을 해제하면 에러가 발생할 것입니다.
           System.out.println(str); // called without the help of an object                       
           System.out.println(StringTest.str);// called with class name  
             } 
         } 


Traceback (most recent call last):

  File "binfilemaking.py", line 5, in <module>

    import matplotlib.pyplot as plt

  File "/usr/local/lib/python2.7/dist-packages/matplotlib/pyplot.py", line 115, in <module>

    _backend_mod, new_figure_manager, draw_if_interactive, _show = pylab_setup()

  File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/__init__.py", line 32, in pylab_setup

    globals(),locals(),[backend_name],0)

  File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_tkagg.py", line 6, in <module>

    from six.moves import tkinter as Tk

  File "/home/testguest/.local/lib/python2.7/site-packages/six.py", line 203, in load_module

    mod = mod._resolve()

  File "/home/testguest/.local/lib/python2.7/site-packages/six.py", line 115, in _resolve

    return _import_module(self.mod)

  File "/home/testguest/.local/lib/python2.7/site-packages/six.py", line 82, in _import_module

    __import__(name)

  File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 42, in <module>

    raise ImportError, str(msg) + ', please install the python-tk package'

ImportError: No module named _tkinter, please install the python-tk package


라는 에러가 발생하였습니다. 이제 해결하는 방법을 알아보겠습니다.


시스템에서 제공하는 Python과 함께 사용하기 위해 로컬에서 Tkinter를 설치하는 것은 그리 쉽지 않습니다.


소스에서 빌드 할 수도 있지만, 이것은 가장 좋은 아이디어는 아닙니다.

일반적으로 실행중인 바이너리 패키지 기반 배포판에서....


apt-get python-tk 를 컴퓨터에 설치하는 것이 더 안전합니다. (Ubuntu와 같은 데비안에서 파생 된 배포판에서 작동하며 다른 배포판의 패키지 관리자 및 패키지 목록을 참조하십시오.)

그러면 리눅스에서

sudo apt-get install python-tk

를 입력합니다.

그러면 설치 진행 Y를 하시면 해결됩니다.


'Computer_IT > Python' 카테고리의 다른 글

Python Requests 설치하기 및 크롤링(scraping) 예제  (0) 2017.05.12

matplotlib 설치하기

  -- png, freetype 에 대한 사전 설치 요함.


sudo apt-get install libpng-dev

sudo apt-get install libfreetype6-dev


sudo apt-get install libjpeg8-dev

     ---> jpeg 도 그냥 설치함.. 


sudo pip install matplotlib


+ 지난 텐서플로우 게시글에 이어서 튜토리얼 2를 진행하겠습니다.

+ 적힌 부분이 추가설명 및 의견입니다.. ㅎㅎ


  기계 학습에 대한 자세한 내용은이 튜토리얼의 범위를 벗어난다. 

그러나 TensorFlow는 손실 함수를 최소화하기 위해 각 변수를 천천히 변경하는 옵티 마이저를 제공합니다.

 가장 간단한 옵티 마이저는 그래디언트 디센트입니다. 

해당 변수에 대한 손실 파생의 크기에 따라 각 변수를 수정합니다. 일반적으로 심볼릭 파생물을 수동으로 계산하는 것은 지루하고 오류가 발생하기 쉽습니다. 

결과적으로 TensorFlow는 tf.gradients 함수를 사용하여 모델 설명 만 제공된 파생물을 자동으로 생성 할 수 있습니다. 단순화를 위해 일반적으로 옵티마이 저가이를 수행합니다. 


+ 마땅한 번역할 단어가 안떠올라서 마지막 구글 번역을 돌렸더니 단어가 이상하네요 추가적으로 예제 코드를 보면서 설명하겠습니다.


예를 들어,


optimizer = tf.train.GradientDescentOptimizer(0.01)
train
= optimizer.minimize(loss)
sess.run(init) # reset values to incorrect defaults.
for i in range(1000):
  sess
.run(train, {x:[1,2,3,4], y:[0,-1,-2,-3]})

print(sess.run([W, b]))



이제 실제 기계 학습을했습니다!

+ 이번 코드는 GradientDescentOptimizer 0.01비율로 손실을 최소화 시키고 선형 모델인 

+ y = Wx+b 에서 x값과 y값을 주어졌을 때, W와, b의 값을 1000번의 학습된 결과를 통해 

+ 값을 표현한 것입니다.


 이 간단한 선형 회귀를 수행하더라도 TensorFlow 핵심 코드가 많이 필요하지는 않지만 모델에 데이터를 입력하는 더 복잡한 모델과 메서드는 더 많은 코드가 필요합니다.

 따라서 TensorFlow는 일반적인 패턴, 구조 및 기능에 대해 더 높은 수준의 추상화를 제공합니다. 

우리는 이어서 이러한 추상화를 사용하는 방법을 배웁니다.


완료된 프로그램 

완성 된 훈련 가능한 선형 회귀 모델은 다음과 같습니다.


import numpy as np
import tensorflow as tf

# Model parameters
W
= tf.Variable([.3], tf.float32)
b
= tf.Variable([-.3], tf.float32)
# Model input and output
x
= tf.placeholder(tf.float32)
linear_model
= W * x + b
y
= tf.placeholder(tf.float32)
# loss
loss
= tf.reduce_sum(tf.square(linear_model - y)) # sum of the squares
# optimizer
optimizer
= tf.train.GradientDescentOptimizer(0.01)
train
= optimizer.minimize(loss)
# training data
x_train
= [1,2,3,4]
y_train
= [0,-1,-2,-3]
# training loop
init
= tf.global_variables_initializer()
sess
= tf.Session()
sess
.run(init) # reset values to wrong
for i in range(1000):
  sess
.run(train, {x:x_train, y:y_train})

# evaluate training accuracy
curr_W
, curr_b, curr_loss  = sess.run([W, b, loss], {x:x_train, y:y_train})
print("W: %s b: %s loss: %s"%(curr_W, curr_b, curr_loss))



+ 이 코드의 함수를 시각화 해서 본다면

TensorBoard final model visualization



tf.contrib.learn


tf.contrib.learn은 다음을 포함하여 기계 학습의 메커니즘을 단순화하는 상위 TensorFlow 라이브러리입니다.

-실행중인 학습 루프

-평가 루프 실행

-데이터 세트 관리

-수유 관리

tf.contrib.learn은 많은 공통 모델을 정의합니다.


기본 사용법

tf.contrib.learn을 사용하면 선형 회귀 프로그램이 얼마나 단순 해지는 지 주목하십시오


import tensorflow as tf
# NumPy is often used to load, manipulate and preprocess data.
import numpy as np

# Declare list of features. We only have one real-valued feature. There are many
# other types of columns that are more complicated and useful.
features
= [tf.contrib.layers.real_valued_column("x", dimension=1)]

# An estimator is the front end to invoke training (fitting) and evaluation
# (inference). There are many predefined types like linear regression,
# logistic regression, linear classification, logistic classification, and
# many neural network classifiers and regressors. The following code
# provides an estimator that does linear regression.
estimator
= tf.contrib.learn.LinearRegressor(feature_columns=features)

# TensorFlow provides many helper methods to read and set up data sets.
# Here we use `numpy_input_fn`. We have to tell the function how many batches
# of data (num_epochs) we want and how big each batch should be.
x
= np.array([1., 2., 3., 4.])
y
= np.array([0., -1., -2., -3.])
input_fn
= tf.contrib.learn.io.numpy_input_fn({"x":x}, y, batch_size=4,
                                              num_epochs
=1000)

# We can invoke 1000 training steps by invoking the `fit` method and passing the
# training data set.
estimator
.fit(input_fn=input_fn, steps=1000)

# Here we evaluate how well our model did. In a real example, we would want
# to use a separate validation and testing data set to avoid overfitting.
print(estimator.evaluate(input_fn=input_fn))



 {'global_step': 1000, 'loss': 1.9650059e-11}

+ 위 처럼 결과가 나올 것입니다.



커스텀 모델


tf.contrib.learn은 사용자를 미리 정의 된 모델로 잠그지 않습니다. 

TensorFlow에 내장되어 있지 않은 커스텀 모델을 만들고 싶다고 가정 해 보겠습니다. 

tf.contrib.learn의 데이터 세트, 수유, 교육 등의 높은 수준의 추상화는 여전히 유지할 수 있습니다. 

설명을 위해, 우리는보다 낮은 수준의 TensorFlow API에 대한 지식을 사용하여 LinearRegressor에 대한 자체 등가 모델을 구현하는 방법을 보여줍니다.


tf.contrib.learn과 작동하는 사용자 정의 모델을 정의하려면 tf.contrib.learn.Estimator를 사용해야합니다. tf.contrib.learn.LinearRegressor는 실제로 tf.contrib.learn.Estimator의 하위 클래스입니다. 

Estimator를 하위 분류하는 대신 Estimator에게 예측, 교육 단계 및 손실을 평가할 수있는 방법을 

tf.contrib.learn에게 알려주는 model_fn 함수를 제공하기 만하면됩니다. 코드는 다음과 같습니다.


import numpy as np
import tensorflow as tf
# Declare list of features, we only have one real-valued feature
def model(features, labels, mode):
 
# Build a linear model and predict values
  W
= tf.get_variable("W", [1], dtype=tf.float64)
  b
= tf.get_variable("b", [1], dtype=tf.float64)
  y
= W*features['x'] + b
 
# Loss sub-graph
  loss
= tf.reduce_sum(tf.square(y - labels))
 
# Training sub-graph
  global_step
= tf.train.get_global_step()
  optimizer
= tf.train.GradientDescentOptimizer(0.01)
  train
= tf.group(optimizer.minimize(loss),
                   tf
.assign_add(global_step, 1))
 
# ModelFnOps connects subgraphs we built to the
 
# appropriate functionality.
 
return tf.contrib.learn.ModelFnOps(
      mode
=mode, predictions=y,
      loss
=loss,
      train_op
=train)

estimator
= tf.contrib.learn.Estimator(model_fn=model)
# define our data set
x
= np.array([1., 2., 3., 4.])
y
= np.array([0., -1., -2., -3.])
input_fn
= tf.contrib.learn.io.numpy_input_fn({"x": x}, y, 4, num_epochs=1000)

# train
estimator
.fit(input_fn=input_fn, steps=1000)
# evaluate our model
print(estimator.evaluate(input_fn=input_fn, steps=10))




커스텀 모델 () 함수의 내용이 저수준 API의 수동 모델 트레이닝 루프와 얼마나 흡사한지 주목하십시오.



다음 단계


이제 TensorFlow의 기본 지식을 습득했습니다. 우리는 더 많은 것을 배우기 위해 여러분이 볼 수있는 튜토리얼을 몇 가지 더 가지고 있습니다. 초보자의 경우 초보자 인 경우 MNIST를 참조하십시오. 그렇지 않은 경우 전문가를위한 Deep MNIST를 참조하십시오


+ 다음 튜토리얼은 손글씨 인식을 하는 것입니다.

+ 이번 튜토리얼에서는 API에서 얼만큼 잘 제공해주는지 알려주는 것 같았습니다.

+ 다음 튜토리얼 부터는 점점 머신러닝과 관련하여 인곤지능과 가까워질 것 입니다. 

+ 다 같이 힘내봅시다.








[MYSQL] SELECT 한 내용 INSERT 시키는 방법

Select 한 내용을 그대로 Insert 시키는 방법과 약간 응용하는 법을 소개합니다. 처음에는 저도 방법이 정확히 떠오르지 않아 구글링을 했지만 간단명료하게 나와있는 글이 없어 시간을 좀 뺐겼던 기억이 납니다.

1. select 한 내용의 전체 컬럼 Insert

당연한 이야기지만 select하는 테이블과 insert할 테이블의 컬럼은 일치해야 합니다.

 

2. 원하는 컬럼만 select 해서 Insert

PRIMARY키가 있어 1번의 방법으로 INSERT가 안되는 경우 PRIMARY키를 제외한 컬럼을 직접 선택해서 INSERT하는 방법입니다.


++

위의 글을 참조한 이유는 잘 동작하던 쿼리문이

UID를 추가한 이후 

Column count doesn't match value count at row 1 의 에러 문구가 나왔었다.

실제 소스를 보면서 설명하겠습니다.


insert into HPG

select system, cbroff, consl from CNS

where system = system ; 


일 경우 에러가 없던 문구에서

Column (UID)를 추가하였습니다. 했더니 에러 문구가 위의 msgbox로 출력되었습니다.


즉 From table과 Insert Table의 컬럼 수가 일치하지 않다는 것으로 판단됩니다.


따라서, UID는 자동 증가이기 때문에


insert into HPG(system, cbroff, consl)

select system, cbroff, consl from CNS

where system = system ;


를 추가 함으로 써 에러를 수정할 수 있었습니다.

'Computer_IT > MySQL' 카테고리의 다른 글

[DB] 인덱스 란? / 인덱스 유,무 의 차이점  (0) 2017.05.24

리눅스 CMOS -- 시간 확인


 CMOS 시간 확인 

# clock -r    


시스템 시간 확인 

# date        


# date +%Y-%m-%d

2011-11-23


CMOS -- 시간 설정

 시스템시간을 CMOS시간으로 설정 

# clock -w   

 CMOS시간을 시스템시간으로 설정 

# clock -s    


리눅스 -- 시간 동기화


리눅스 시스템 시간 동기화 

# rdate -s time.bora.net  


시간 확인 

# date                          


 CMOS 시간에 적용 

# clock -w                   


인덱스 (데이터베이스)

위키백과, 우리 모두의 백과사전.

인덱스(영어: index)는 데이터베이스 분야에 있어서 테이블에 대한 동작의 속도를 높여주는 자료 구조를 일컫는다. 인덱스는 테이블 내의 1개의 컬럼, 혹은 여러 개의 컬럼을 이용하여 생성될 수 있다. 고속의 검색 동작뿐만 아니라 레코드 접근과 관련 효율적인 순서 매김 동작에 대한 기초를 제공한다. 인덱스를 저장하는 데 필요한 디스크 공간은 보통 테이블을 저장하는 데 필요한 디스크 공간보다 작다. (왜냐하면 보통 인덱스는 키-필드만 갖고 있고, 테이블의 다른 세부 항목들은 갖고 있지 않기 때문이다.) 관계형 데이터베이스에서는 인덱스는 테이블 부분에 대한 하나의 사본이다.

인덱스는 고유 제약 조건을 실현하기 위해서도 사용된다. 고유 인덱스는 중복된 항목이 등록되는 것을 금지하기 때문에 인덱스의 대상인 테이블에서 고유성이 보장된다.



+ 인덱스는 특정 칼럼 값을 가지고 있는 열 혹은 값을 빠르게 찾기 위해서 사용된다. 

+ MySQL은 첫 번째 열부터 전체 테이블에 걸쳐서 연관된 열을 검색하기 때문에 테이블이 크면 클 수록 비용이 엄청나게 늘어난다. 

+ 만약 테이블이 쿼리에 있는 컬럼에 대한 인텍스를 가지고 있다면, 

+ MySQL은 모든 데이터를 조사하지 않고도 데이터 파일의 중간에서 검색위치를 빠르게 잡아낼 수 있다. 

+ 인덱스 위주 검색 후, 관련된 혹은 원하는 데이터들을 가져올 수 있다고 생각할 수도 있다.



인덱스를 사용하는 이유 

WHERE 구문과 일치하는 열을 빨리 찾기 위해서.

열을 고려 대상에서 빨리 없애 버리기 위해서. 

조인 (join)을 실행할 때 다른 테이블에서 열을 추출하기 위해서.

특정하게 인덱스된 컬럼을 위한 MIN() 또는 MAX() 값을 찾기 위해서.

사용할 수 있는 키의 최 좌측 접두사 (leftmost prefix)를 가지고 정렬 및 그룹화를 하기 위해서.

데이터 열을 참조하지 않는 상태로 값을 추출하기 위해서 쿼리를 최적화 하는 경우에.


인덱스를 사용해야 하는 경우 

데이터 양이 많고 검색이 변경보다 빈번한 경우

인덱스를 걸고자 하는 필드의 값이 다양한 값을 가지는 경우 


   인덱스의 사용 


  기존의 테이블에 인덱스를 추가하기 

ALTER TABLE  테이블명 ADD INDEX(필드명(크기));


mysql> ALTER TABLE temp ADD INDEX(keyword(20));

Query OK, 554604 rows affected (1.31 sec)

Records: 554604  Duplicates: 0  Warnings: 0



  테이블 생성시 인덱스 추가하기 
CREATE TABLE 테이블 명 ( 필드명 데이터타입(데이터크기), 
INDEX(필드명(크기)) ENGINE MyISAM; 

mysql> CREATE TABLE test (
    -> keyword varchar(20),
    -> INDEX(keyword(20)))
    -> ENGINE MyISAM;
Query OK, 0 rows affected (0.11 sec)


  FULLTEXT 인덱스 만들기 
일반적인 인덱스와는 달리 MySQL의 FULLTEXT는 매우 빠르게 모든 텍스트 열을 검색한다. 검색 엔진과 유사한 방법으로 자연 언어를 이용해 검색할 수 있는 특별한 인덱스로 모든 데이터 문자열의 단어를 저장하기 때문이다. 

참고사항 
FULLTEXT 인덱스는 MySQL의 기본 저장 엔진 타입인 MyISAM 테이블에만 사용된다. 
만약 테이블을 MyISAM 으로 변경해야 된다면 
ALTER TABLE 테이블명 ENGINE = MyISAM; 
FULLTEXT 인데스는 CHAR 와 VARCHAR, TEXT 열로만 생성 가능하다.

ALTER TABLE 테이블명 ADD FULLTEXT(필드명)

mysql> ALTER TABLE temp ADD FULLTEXT(keyword);
Query OK, 554604 rows affected (1.49 sec)
Records: 554604  Duplicates: 0  Warnings: 0


  인덱스의 효과 
인덱스를 걸게 되면, 테이블 생성시에 인덱스의 정보도 만들게되므로 생성속도가 느려진다. 


비교를 위해서 두개의 테이블을 생성하였다. 하나는 인덱스가 걸려있는 테이블 (test_index) 와 걸려 있지 않은 테이블 (test)이다. 그림을 보면 생성 속도에서 차이가 꽤 나는 것을볼 수 있다. 

이런데도 인덱스를 거는 이유는 바로 조건문 등에 대한 SELECT 속도 등에서 차이가 나기 때문이다. 

위 테이블의 데이터는 약 55만개의 데이터가 저장되어있다. 그 중에서 '가'로 시작되는 데이터들을 뽑아 오자 .

SELECT * FROM test WHERE keyword LIKE '가%' ; 
5056 rows in set (0.08 sec) 

SELECT * FROM test_index WHERE keyword LIKE '가%' ; 
5056 rows in set (0.01 sec) 



출처: http://ra2kstar.tistory.com/96 [초보개발자 이야기.]


++++

프로시져 내부에서 인덱스를 사용하여 속도 향상을 시켜 보자.

프로시져를 이용하여 2년치의 데이터를 가져올 때, 30초의 대기 시간을 부여한 결과 TimeOut의 결과를 가져왔다.


따라서 프로시져 내부에 인덱스를 부여한 결과 놀라운 속도의 차이를 가져왔다.


프로시져 내용은 

create temporary table tmptbl (cons char(10), custm varchar(60), phone char(50), group char(2), use char(4), 

                               inspe char(8), cd char(8), consl char(5),

                               status char(1), no char(12), reque char(8), INDEX `index1` (consl_no)); 


프로시져 내에서 update 구문이 있어서, 더 오래 걸린 이유도 되었습니다.


하지만 인덱스를 추가한 이후 연관된 데이터의 업데이트 및 select 문이 빠르게 이루어지기 때문에,

타임아웃에도 안걸리고 속도는 향상되는 결과를 얻을 수 있었습니다.


update tmptbl a, something b set a.reque = b.reque,

                     where a.consl_no=b.consl_no;


이처럼 Index는 조건절에 따른 구분이 들어가 있는 것을 선택할 수록 효과는 더 좋습니다.


---

직접 느껴 본 것만 적다 보니깐, 이론적으로 안 맞는 경우도 있는데, 

제가 놓친 정확한 정보와 지식은 댓글로 남겨주시면 감사하겠습니다.










'Computer_IT > MySQL' 카테고리의 다른 글

[MySql]Column count doesn't match value count at row 1 에러  (0) 2017.05.31

TensorFlow 시작하기(설치 이후 첫 튜토리얼)


이 블로그는 첫 번째 튜토리얼을 번역 후 필요에 따라 중간중간 설명을 첨가하였습니다.

원본 글은 https://www.tensorflow.org/ 에 포함되어 있습니다.


이 튜토리얼은 TensorFlow에서 프로그래밍을 시작하도록 안내합니다.

이 게시글을 읽기 전에 TensorFlow를 설치하십시오. 설치 방법은 이전 글에 있습니다.


이 가이드를 최대한 활용하려면 다음 사항을 알아야합니다.

파이썬으로 프로그래밍하는 법. (C#, Java는 해봤었습니다. 뭔가 유저 친화적이지만, 배우지 않았었기 때문에, 미흡한 점은 많습니다만, 구글링 및 튜토리얼 따라하면서 많이 배워가고 있습니다.

처음 하시는 분들도 두려워말고 도전하실 수 있습니다.)

최소한 배열에 대해서는.

이상적으로는 기계 학습에 관한 것입니다. 그러나 기계 학습에 대해 거의 또는 전혀 알지 못하는 경우에도 여전히 읽어야 할 첫 번째 가이드입니다.


TensorFlow는 여러 API를 제공합니다. 최저 수준의 API 인 TensorFlow Core는 완벽한 프로그래밍 제어 기능을 제공합니다. TensorFlow Core는 기계 학습 연구자 및 모델을 미세하게 제어해야하는 사람들에게 권장됩니다. 높은 수준의 API는 TensorFlow Core 위에 구축됩니다. 이러한 상위 수준의 API는 일반적으로 TensorFlow Core보다 배우고 사용하기가 쉽습니다. 또한 상위 수준의 API는 반복적 인 작업을 여러 사용자간에보다 쉽고 일관되게 만듭니다. tf.contrib.learn과 같은 고급 API를 사용하면 데이터 세트, 견적 도구, 교육 및 추론을 관리 할 수 ​​있습니다. 메소드 이름에 contrib가 포함 된 상위 수준의 TensorFlow API 중 일부는 아직 개발 중입니다. 이후의 TensorFlow 릴리스에서 일부 contrib 메소드가 변경되거나 더 이상 사용되지 않을 수도 있습니다. 이 가이드는 TensorFlow Core에 대한 자습서로 시작됩니다. 나중에 tf.contrib.learn에서 동일한 모델을 구현하는 방법을 보여줍니다. TensorFlow를 아는 것보다 핵심적인 API를 사용할 때 핵심 원칙을 통해 내부적으로 일하는 방식에 대한 훌륭한 정신적 모델을 얻을 수 있습니다.


Tensor

TensorFlow에서 데이터의 중심 단위는 텐서입니다. 텐서는 임의의 수의 차원으로 배열 된 프리미티브 값 집합으로 구성됩니다. 텐서의 랭크는 차원 수입니다. 다음은 텐서 (tensors)의 몇 가지 예입니다.

3 # a rank 0 tensor; this is a scalar with shape []
[1. ,2., 3.] # a rank 1 tensor; this is a vector with shape [3]
[[1., 2., 3.], [4., 5., 6.]] # a rank 2 tensor; a matrix with shape [2, 3]
[[[1., 2., 3.]], [[7., 8., 9.]]] # a rank 3 tensor with shape [2, 1, 3]

+ 기존의 알고 있던 데이터 배열과는 살짝 다른 느낌입니다. 즉 집합의 개념으로 사용됩니다.

+ 텐서의 랭크는 차원의 수 라고 되어있는 것 처럼, 각 [ ] 괄호를 주의 깊게 보시면 대략적인 이해에 도움이 될 것입니다.


TensorFlow 핵심 자습서

TensorFlow 가져 오기


TensorFlow 프로그램에 대한 표준 import 문은 다음과 같습니다.


python

>>>  import tensorflow as tf

+ 입력 후 ">>>"가 안보인다면, tensorflow 설치를 완료 안했을 경우가 많습니다. 



이렇게하면 파이썬에서 TensorFlow의 모든 클래스, 메소드 및 심볼에 액세스 할 수 있습니다. 대부분의 문서에서는 이미이 작업을 수행했다고 가정합니다.



The Computational Graph


TensorFlow Core 프로그램은 두 개의 개별 섹션으로 구성되어 있다고 생각할 수 있습니다.


1.계산 그래프 작성. (Building the computational graph.)

2.전산 그래프를 실행합니다. (Running the computational graph.)

계산 그래프는 일련의 TensorFlow 작업을 노드 그래프로 배열 한 것입니다. 간단한 전산 그래프를 작성해 봅시다. 각 노드는 0 이상의 텐서를 입력으로 사용하고 텐서를 출력으로 생성합니다. 노드의 한 유형은 상수입니다. 모든 TensorFlow 상수와 마찬가지로 입력을받지 않으며 내부적으로 저장하는 값을 출력합니다. 다음과 같이 두 개의 부동 소수점 Tensors node1과 node2를 만들 수 있습니다.


node1 = tf.constant(3.0, tf.float32)
node2
= tf.constant(4.0) # also tf.float32 implicitly
print(node1, node2)


마지막 print 서술문은


Tensor("Const:0", shape=(), dtype=float32) Tensor("Const_1:0", shape=(), dtype=float32)


Tensor("Const:0", shape=(), dtype=float32) Tensor("Const_1:0", shape=(), dtype=float32)
Tensor("Const:0", shape=(), dtype=float32) Tensor("Const_1:0", shape=(), dtype=float32)

예상대로 노드 인쇄는 3.0과 4.0 값을 출력하지 않습니다. 대신 평가할 때 각각 3.0과 4.0을 생성하는 노드입니다. 노드를 실제로 평가하려면 세션 내에서 계산 그래프를 실행해야합니다. 세션은 TensorFlow 런타임의 컨트롤과 상태를 캡슐화합니다.


다음 코드는 Session 객체를 만든 다음 run 메소드를 호출하여 node1과 node2를 계산할 수있는 계산 그래프를 실행합니다. 다음과 같이 세션에서 전산 그래프를 실행합니다.

sess = tf.Session()
print(sess.run([node1, node2]))

3.0과 4.0의 예상 값을 봅니다.


Tensor 노드를 연산과 결합하여 더 복잡한 계산을 할 수 있습니다 (연산도 노드입니다). 예를 들어 두 개의 상수 노드를 추가하고 다음과 같이 새 그래프를 생성 할 수 있습니다.

node3 = tf.add(node1, node2)
print("node3: ", node3)
print("sess.run(node3): ",sess.run(node3))

+ 위의 결과되로 표시 되었다면 노드의 값을 tf.add를 통해 합쳐진 것을 볼 수 있습니다.

TensorFlow는 전산 그래프의 그림을 표시 할 수있는 TensorBoard라는 유틸리티를 제공합니다. 다음은 TensorBoard가 그래프를 시각화하는 방법을 보여주는 스크린 샷입니다.

TensorBoard screenshot

+텐서보드의 설치 및 활용 법은 추후 게시글에 올리도록 하겠습니다. 데이터의 흐름도의 이해를 위해 스크린샷 처럼 표시되는구나 정도로 일단 이해하시고 넘어가시면 됩니다.


이 도표는 항상 일정한 결과를 산출하기 때문에 특히 흥미 롭지 않습니다. 자리 표시 자라고하는 외부 입력을 허용하도록 그래프를 매개 변수화 할 수 있습니다. 자리 표시자는 나중에 값을 제공하겠다는 약속입니다.

a = tf.placeholder(tf.float32)
b
= tf.placeholder(tf.float32)
adder_node
= a + b  # + provides a shortcut for tf.add(a, b)

앞의 세 줄은 함수 또는 람다와 비슷하지만 두 개의 입력 매개 변수 (a 및 b)를 정의한 다음 해당 매개 변수에 대한 연산을 정의합니다. feed_dict 매개 변수를 사용하여 이러한 입력란에 구체적인 값을 제공하는 Tensors를 지정하여이 그래프를 여러 입력으로 평가할 수 있습니다.

print(sess.run(adder_node, {a: 3, b:4.5}))
print(sess.run(adder_node, {a: [1,3], b: [2, 4]}))


+ 출력 결과 물은 봣을 때 첫 번쨰 명령 문의 계산식은

3+ 4.5 이고

두번째 계산은

a: 1 + b: 2  = 3

a: 3 + b: 4 = 7

의 결과값을 표현하는 것입니다.


In TensorBoard, the graph looks like this:

TensorBoard screenshot


다른 연산을 추가하여 계산 그래프를 더 복잡하게 만들 수 있습니다. 예를 들어,

add_and_triple = adder_node * 3.
print(sess.run(add_and_triple, {a: 3, b:4.5}))
add_and_triple = adder_node * 3.
print(sess.run(add_and_triple, {a: 3, b:4.5}))
add_and_triple = adder_node * 3.
print(sess.run(add_and_triple, {a: 3, b:4.5}))

+ 연산 : (3+4.5)*3


The preceding computational graph would look as follows in TensorBoard:

TensorBoard screenshot

기계 학습에서 우리는 전형적으로 위와 같은 임의의 입력을 취할 수있는 모델을 원할 것입니다. 모델을 학습 가능하게 만들려면 동일한 입력으로 새로운 출력을 얻기 위해 그래프를 수정할 수 있어야합니다. 변수를 사용하면 그래프에 학습 가능한 매개 변수를 추가 할 수 있습니다. 그것들은 타입과 초기 값으로 구성됩니다 :

W = tf.Variable([.3], tf.float32)
b
= tf.Variable([-.3], tf.float32)
x
= tf.placeholder(tf.float32)
linear_model
= W * x + b

상원 의원은 제소자를 호출 할 때 값이 변하지 않을 것입니다. 반대로 할 수 없습니다. TensorFlow 프로그램의 모든 변수를 다음과 같이 사용하십시오.

init = tf.global_variables_initializer()
sess
.run(init)

init이 모든 전역 변수를 초기화하는 TensorFlow 하위 그래프의 핸들임을 인식하는 것이 중요합니다. sess.run을 호출 할 때까지 변수는 초기화되지 않습니다.


x는 자리 표시 자이므로 다음과 같이 x의 여러 값에 대해 linear_model을 동시에 평가할 수 있습니다.


print(sess.run(linear_model, {x:[1,2,3,4]}))


+ x를 순차적으로 대입하면서 출력하는 것을 볼 수 있습니다.


우리는 모델을 만들었지 만 아직 얼마나 좋은지 모릅니다. 훈련 데이터에 대한 모델을 평가하려면 원하는 값을 제공하기 위해 y 자리 표시자가 필요하며 손실 함수를 작성해야합니다.



손실 함수는 제공된 모델로부터 현재 모델이 얼마나 떨어져 있는지를 측정합니다. 현재 모델과 제공된 데이터 사이의 델타의 제곱을 합한 선형 회귀에 표준 손실 모델을 사용합니다. linear_model - y는 각 요소가 해당 예제의 오류 델타 인 벡터를 만듭니다. tf.square를 호출하여 오류를 제곱합니다. 그런 다음 모든 제곱 된 오류를 합하여 tf.reduce_sum을 사용하여 모든 예제의 오류를 추상화하는 단일 스칼라를 만듭니다.


y = tf.placeholder(tf.float32)
squared_deltas
= tf.square(linear_model - y)
loss
= tf.reduce_sum(squared_deltas)
print(sess.run(loss, {x:[1,2,3,4], y:[0,-1,-2,-3]}))




W와 b의 값을 -1과 1의 완벽한 값으로 재 할당하여 수동으로 향상시킬 수 있습니다. 변수는 tf.Variable에 제공된 값으로 초기화되지만 tf.assign과 같은 연산을 사용하여 변경할 수 있습니다. 예를 들어, W = -1 및 b = 1은 우리 모델에 대한 최적의 매개 변수입니다. 그에 따라 W와 B를 변경할 수 있습니다.


fixW = tf.assign(W, [-1.])
fixb
= tf.assign(b, [1.])
sess
.run([fixW, fixb])
print(sess.run(loss, {x:[1,2,3,4], y:[0,-1,-2,-3]}))

마지막 인쇄는 손실이 0임을 보여줍니다.


우리는 W와 B의 "완벽한"값을 추측했지만 기계 학습의 요점은 올바른 모델 매개 변수를 자동으로 찾는 것입니다. 다음 섹션에서이를 수행하는 방법을 보여줄 것입니다.




+ 지금은 손실이 0 인 것인 것처럼 간단한 계산식으로 했지만, 나중에 갈 수록 소수도 나오고 손실율도 커서 더 정확한 모듈을 만들기 위한 작업을 하겠습니다.


+ 일단 이번 글에서는 간단한 이해 및 원리만 이해하시면 되겠습니다.



+ Recent posts