2013년 7월 8일 월요일

잠 못 이루는 밤

일요일 1시 ...게시판에 힘내라고 글을 쓰고....
6시까지 잠이 오지 않아서 그냥 그냥 책을 보다가...영화를 보다가...

산소 먹는 해나
병원 복도에서 행복해 하는 해나를 모니터로 다시 보고 건강해지길 원했는데

오후 늦게 이미 떠났다는 글을 보고 당황 스러움이란...

알지도 못하는 3자가 이럴지인데...해나의 부모님과 언니...가족들은 준비가 되었을까...

아마도 의식이 없었을 해나는 어땠을까

해나가 돌아오면 꼭 한번 만나러 가야겠다...

단지 이 감정이 살다가 갑자기 한번 지나가는 바람일 지라도 자신에게 이런 감정이입이 있을 것이라고는 생각 못했던 나로써는 이것도 당황스럽다

양말속에 손
해나만의 인사
"응!" 을 표현하는 밝은 표정
해맑은 웃음
중환자실 침대위 혼자 놀고 있는 해나 
주사가 무서운 해나
파울로박사의 물음에 힘차게 끄덕이던 모습
응급차를 타기전 이별이 싫은 해나...
사탕....코에 바른 사탕....첫 향기
손으로 입을 가리고 화사하게 웃는 모습

어떤 부모가 이 아이를 살리기 위해 도박같은 결정을 하지 않을 수 있었을까 

후회가 될것이고 아이를 보낸것 같아 힘들겠지만 해나의 부모님들이 잘 이겨내기를 기원해 본다.  언니인 대나도 있으니 더욱 열심히 살아갈것이라 믿어의 심치 않으며...

한동안 해나 열병이 지나가길 기다려야 겠다.
마음이 아프다...겨우 이렇게 키보드나 또각 거리는 자신이 무기력하다

2013년 7월 7일 일요일

해나가 하늘 나라로 갔습니다....2013년 7월 7일 05시 30분 경 (GMT+9)

천사가된 해나에게 아저씨가

먹먹한 가슴이 어찌 해야 할 바를 모르겠고...
만감이 교차하는 마음에 글 한줄 적어보기도 어려운 하루가 지나갑니다....
해나야.... 널 주려고 대려온 하얀 호랑이 인형은 아저씨가 가지고 있으려고....
더 해 줄 수 있는 것이 없어 미안하고...
하지만 해나 덕분에 아저씨는 아저씨 아이들을 더 사랑하는 방법을 알게 된것 같내...
고마워....


http://www.m-letter.or.kr/lb/mboard.asp?Action=view&strBoardID=haena&intSeq=160113




====================================

2013년 6월 여름이 얼마 남지 않았지만 미리부터 덥기 시작한 어느날
집에서  시간을 보내다 TV 다큐 사랑을 힐끗 보았다.
잠깐 스친 해나의 얼굴 ... 하지만  "어디 아픈 아이인가 보다...." 하는 생각을 잠시하고 그냥 지나간 시간

6월 말 너무 더운데.... 평소 버스의 짜증스러움에 음악이나 듣던 내가 
다행이 버스에 에이컨이 빵빵하게 나온날
땀을 식히고 습관적으로 휴대폰을 가지고 놀다가 어찌 어찌 링크가 "해나의 기적" 이라는 링크를 타고 올랐다.

손을 양말에 넣었다가 "짠~!" 하는 모습이 너무 귀여워서 돌려 보기를 몇 번....

유튜브에 올라온 짧은 동영상들을 보면서 집에 오는길 혼자 찡해지를 코를 잡고  어찌할 바를 몰라했던 저녁 
다시보기를 하기 위해  절대 가입하지 않을꺼라 다짐했던 MBC 사이트에 어쩔 수 없이 가입을 하고  해나를 만나게 되었다.

해나는 8월 22일생...아라는 9월 1일생 하지만 같은 해는 아니고 딱 1살 차이가 난다. 해나는 올해 네살 (한국나이) 나의 둘째딸은 세살이 된다.

첫째와 십년 터울의 둘째를 만나고 나니 너무나 행복했다. 
그 감정이 해나를 보면서 더욱 감정이입을 만들어 냈는지도....

국내 사이트에는 기부기간이 종료되어 기부도 않되고 어디다 도움을 주어야 할 지 몰라서 외국 기부 사이트에 드르고 책이 출간 되었기에 몇권을 사서 주변에 돌려 읽으며 
해 줄 것이 너무 없어 미안함에 해나 이야기를 여러사람에게 전달하는 것이 돕는게 아닐까 하는 생각을 했었나 보다 

오늘 해나의 소식을 듣고 책을 들고...한손에는 인형을 들고 
이런상황은 생각해 보지 못했던 어리석음에 당황스럽고 황망해 한다.
마음속으로 생각을 했었는데.... 미안하지만 내 딸도 아니고...예쁘기는 하지만..... 이라는 생각으로 살짝 갭을 유지하려고 했던 마음이 분명히 있었는데....

이 아린마음은 무었이고 이 글을 적으면서 흐르는 눈물은 무었일까

미안하지만 솔직한 마음은... 천사가 된 해나에게 인사를 전하고 싶었다. 
넌 어리지만 덕분에 아저씨는 내 아이들을 바라보는 새로운 시각을 가지게 되어 너무 고맙다고 

태어나서 길지 않은 그 시간동안 겨우 병실과 복도를 통해 세상을 바라본 아기가 저 먼 타국땅에서... 그래도 사랑하는 엄마 아빠와 언니...가족들이 곁에 있어서 조금은 덜 원망 스러웠을까?

아무리 착한 사람도 아프면 짜증도 부르고 화도 내던데... 세살이면 다 알 나이에 겨우 표정과 몸짓으로 어떤 말을...어떤 원망을....어떤 사랑을 ... 어떤 위로를 표현하고 싶었을까....

해나...해나야.....해나야.........

2013년 7월 4일 목요일

오래된 자동차 자가 수리 후기(카렌스 LPG 1.8 2000년식)


카렌스 DIY 수리 들어갑니다.

교체 대상 :
기화기
점화코일, 플러그배선, 점화플러그, 로터, 분배기
수온센서, 써머스텟, 산소센서
청소대상 : 
ISC 밸브청소, 스로틀밸브 청소, 기타....

누가 그랬던가 공부의 시작은 청소라고....
작업시작전 일단 작업 준비 부터..... 캠핑용 테이블까지 펼쳐 놓고 공구준비

오랜만에 카렝이 속을 들여다 봅니다...  딱봐도 가운데가 엔진,
우측은 베터리 및 공조장치
센터상부는 믹서 및 스로틀밸브
좌측 상단이 기화기


좀 자세히 보자면 좌측 상단 안쪽으로 짱박힌 녀석이 기화기 되겠음
현 상태는..... 시동 일발로 안걸리고.... 타르 코크 열어도 타르 배출이 안됨(내부가 막힌듯)

점화 플러그 배선이 엔진으로 들어가는게 보이죠?
배선이 끼워져 있는 녀석이..이름이...뭔가 있는데 그냥 분배기라고 부르도록 하죠
분배기 안에는 로터라는 녀석이 엔진 축이 돌면 같이 돌면서 스파크를 순서대로 튀겨지도록 빙글빙글 도는 놈이 있습니다.

분배기에 엔진으로 들어가는 선 말고 1개가 옆으로 빠져서 아래 시커먼 녀석에 연결되는데요 이놈이 점화코일 입니다. 요즘 차들은 점화플러그 배선에 독립형으로 점화코일이 있는 놈들이 대부분 입니다.  교환하려면 케이블 가격이 겁내 비싸죠....
카랭이는 코일 1개에서 4개의 플러그로 전압을 전달하기 때문에 케이블이 1만원대 뿌니 안해요...

이녀석의 일은 점화플러그에 전압을 튀기기 위해 천볼트 단위로 전압을 올려주는 역할을 합니다. 이놈이 비실비실하면  플러그를 갈아도 비실비실 하지요.  무지 오래되서 맛이 가지 않는 이상 자주 갈아줄 필요가 없는 놈이지만 제 차는 13만에 한번도 안갈은 것이 분명하므로 교체 대상으로...

이상한 통이 있는데 이놈은 별거 아님..그냥 앞쪽 공기끌어다가  일명 밥통(안에 필터가 있어 외기 먼지를 걸러서 엔진에 공급)으로 넣어주는 그냥 속빈 프라스틱 통입니다. 뿌개지지 않으면 손댈일 없죠

일단 점화플러그를 교환 합니다.  16mm 점화 플러그 렌치가 필요합니다. 깁숙히 들어있기 때문에 전용공구 필요하죠...얼마 안합니다. 센터가서 플러그 교체할 돈으로  공구사서 직접 갈면 돈 남아요...

중간 프라스틱의 나사를 풀고 나면  케이블이 끼워진 것이 보입니다. 뽑아 냅니다. 잘 안빠지면 뺀찌로 뽑아도 됩니다. (케이블은 버릴꺼니까!! 전 항상 플러그와 케이블을 같이 교환합니다)
참...그리고 배선 뽑을때 처음 모습을 찍어놓거나 하세요

엔진 좌측부터 1,2,3,4 이고 분배기에 보면 숫자가 있기는 하지만 보기 구찮습니다. 잘 모르면 그냥 사진 하나 찍어놓고 나중에 연결할때 사진보고 위치에 바르게 끼워야 합니다.
순서 잘못 넣으면 엔진에서 병맛이 납니다....

케이블을 뽑고나서  렌치로 플러그를 잡고 좌측으로 돌려서 뺍니다. 잘 안빠지면 WD40 뿌리고 한참 놀다가 다시한번 해보시고...
차 고칠때 무식하게 힘써서 뭔가 하려고 하다가는 돈 엄청 들어갑니다. 조심하세요

뽑아낸 플러그와 새것입니다. 차이가 좀 나죠??  옛날에는 간극조절도 하고 그런다고 했는데...그런 비싼 백금 플러그나 이리둠 뭐 그런거고 난 정품(개당 돈천원 함)으로 그냥 바꿔버릴꺼니 기존것으로 그냥 퇴출

저번에 플러그 교환시 덜 조였나...안쪽까지 녹이 들어갔내요...이런 안됨...
너무 꽉 조여서 엔진 조지면 중고차는 폐차수준까지 ...(해드 가는비용이 엄청 비싸게 나옴..) 그렇다고 너무 살살 조여 놓으면 그것도 작살....
적당히...(처음 풀기 전에 플러그 박스에 있는 설명서를 잘 읽어보고 처음 위치를 기억해서 살살 돌려서 잘 들어가는대 까지 돌리고 일 부 조금더 조여주도록....)

으흠.. 드럽내.... 케이블을 싸구려 썼더니 케이블 고무가 녹아서 묻어났다는...정품 씁시다..


전 수온 센서도 갈아야 하기 때문에 플러그만 끼워놓고 케이블은 연결 하지 않고 나중에 합니다.
두번째로는 전압을 분배하는 분배기 부분과 안에 빙글빙글 돌면서 접압을 타이밍에 맞추어 전달하는 로터를 교환 합니다. 나사 3개 풀면 됩니다.

좌측이 쓰던거 우측으 신삥

저 네개의 핀으로 전압아 튀면서 플러그로 전달 되는건데요...오래 되어서 모서리가 달아 사선으로 깎여 있는게 보입니다.

새것은 이렇게 날이 서있습니다.

로터가 차이가 많이 나내요.. 고전압이 지나가기 때문에 먼지가 많이 낍니다. 아무래도 전압 흐름에 영향을 주겠죠?


플러그, 분배기, 로터 교환 완료 하고 이제 센서 교환을 위해서  밥통과 플로어 부분을 들어냈습니다.

 중상단에 회색 프라스틱 머리를 가진 녀석이 하나 끼워져 있죠?
이놈이 수온센서입니다.
중간 부분에 실리콘이 튀어나와 있는 덮게가 있는데 이놈을 빼내면 써머스텟을 교환 할 수 있습니다.

써머스텟을 교환 하려고 했으나 아래쪽 볼트는 탈거하는데 미션의 오일파이프와 간섭이 있습니다...고민하다가 그냥 포기....써머스텟 역시 온풍이 나오지 않거나 엔진이 과열 되지 않는이상 큰 고장 없는 놈이므로 멀쩡하다고 판단되어 일 저지르지 않기 위해 그냥 두기로 했습니다.

써머스텟은 냉각수의 온도에 따라서 냉각수를 흐르게 하거나 차단합니다. 카렌스는 열리는 온도가 88도인 써머스텟을 사용합니다. 즉 엔진에 시동이 걸리고 냉각수 온도가 88도가 되면 써머스텟이 열리면서 냉각수 순환이 시작됩니다. 고로 고장나서 열리지 않거나(엔진과열현상)....열려서 닫히지 않거나(엔진이 적정하게 달궈지지 않아서 실내 온풍히터가 안나오거나... 차량예열에 시간이 오래걸림) 하면 냉각계통에 장애를 일으킵니다.

수온센서는 엔진 내부로 흘러가는 냉각수의 수온을 체그 합니다. 차량 계기판에 나오는 수온게이지가 이놈에게 의지 합니다. 그리고 이 온도를 ECU(차에 있는 컴퓨터라고 보면 됨)에서  판단하여 팬을 돌리거나 과열되면 에어컨을 강제 차단하거나...뭐 그런 일을 합니다. 수온센서가 나가면...잘못하면 차가 퍼지지요...하지만 웬만해서는 고장나거나 그런 녀석이 아닙니다.   저는 차가 오래 되서 교환 합니다.
실제 분리해서 보니 그다지 크게 더럽지도 않았습니다.

일단 수온센서 교환은 조금 있다가 하기로...


이번에는 기화기 차례입니다.
기화기를 뜯어내면 엔진에서 나오는 냉각수가 기화기를 통과하기 때문에 냉각수 라인을 뺄때 냉각수가 흐를 수 있습니다.
카렌스는 기화기 아래에 발전기와 에어컨 압축기 들이 있습니다. 필히 아래쪽에 비닐을 대고 분리 하시고  저의 경우 미리 시작할때 냉각수를 빼고 작업했습니다.
그래도 조금은 흘러나오므로 냉각수를 빼고 작업하더라도 아래쪽에 걸래라도 대어놓고 작업하세요   (냉각수는 부식성이 높아서 문제가 됩니다.)

처음 뜯어보는 기화기...
기화기는 봄베(가스가 들어있는 연료통)에서 액체 상태로 전달된 가스의 기압을 조정하여 기체 상태로 변경하는 역할을 합니다. 사진상에 아래쪽에 동관이 봄배에서 가스가 들어오는 관 입니다...
아...이놈 탈거가 쉽지 않습니다.  두세번 쉬어가면서 한시간 정도 낑낑  거렸습니다. 전문가라면 금방 했을 것인데....혹시나 찟어지면 X 될것 같아서 조심조심 하느라.... 좁아서 작업 공간도 잘 안나옵니다.

냉각수 입/출수관, 가스 출구, 솔레노이트 전선을 탈거하고나서 기화기를 앞으로 잡아댕겨 뺍니다. 안그러면 아래쪽 가스관을 풀 수 가 없어서...
조심조심 댕겨 봅니다. 이게 엄청 여유가 있는것도 아니고 해서 아래쪽에 손으로 댕겨가면서 동관이 찟어지거나 꺽이지 않도록 답아 당겨 빼냅니다.

겨우겨우 스페너를 넣을 공간을 만들었습니다.

!!  초기 작업시작전에 시동을 걸고 가스차단 밸브를 눌러서 남아 있던 가스를 다 태우고 작업을 하세요. 시동을 끄면 봄베의 벨브가 차단되기는 하지만 관속과 기화기에 남아 있언 가스가 분해시 배출 되면서 깜짝! 놀랄 수 있습니다. 

당연히 우측이....
좌측 재생 기화기는 인터넷에서(11번가) 9만원 주고 샀습니다. 교환 후 기존 제품을 보내주면 1만원을 통장에 넣어 준다니...8만원 이라고 하면 되겠내요

수온센서를 교체하려고 그쪽에도 아래쪽에 비닐을 대어봅니다. (혹시나해서)
초기에 냉각수를 빼고 작업해서 나중에 빼내어 보니 냉각수가 흐르지는 않았습니다만 그냥 대놓고 하는걸로....


수온센서와 연결된 케이블을 분리하고.....엉???
이걸 보니 핀이 두개짜리??? 분명히 주문한건 3핀 짜리인데...
젠장...인터넷을 너무 믿었습니다. 인터넷에 있는 품번으로 주문한건데 내 차와 안맞습니다..... 내차는 2P 주문한건 3P..... 어디서 잘못된걸까..고민하닥 그냥..... 근처 KIA센터 가서 말씀 드렸더니 부품을 주문해 주셔서 5천원주고 2P 수온센서를 구매했습니다. (쓸대 없이 돈더 썼음)


 아놔...그리고.... 공구가 몇개 더 있어야 하겠습니다.
스페너가 없어서 몽키스페너로 돌리려고 하니 빠가만 나고 분리가 안됩니다. -.-;;
복스알로 빼려고 하니 프라스틴 부분이 길어서 끼워지지 않고....
결국 프라스틱 단자를 뽀개 버립니다 -.-;;;
복스알을 끼워서 빼내고....새것으로...
(수온 센서 교환은 이번 작업에서 뻘짓이라고 단정지었음..이거 안갈아도 될껄...삽질을 했음)


산소센서도 사온 부품이 핀이 맞지 않습니다..... 젠장 호환되는 산소센서라고 했는데..핀이 안맞아....... 산소 센서가격이 3만 5천원 인데...젤 비싼대...결국 산소센서도 그냥 포기

구입한 부품중에서  서머스텟과 산소센서는 그냥 교환 포기.... 정말 고장나면 그때나 갈지뭐....

이렇게 해서 카랭이 DIY 정비를  7시간 정도 걸려서 작업했습니다.

duty값을 기계로 조정한게 아닌지라 RPM이 좀 높은 것을 빼고는 
조용해 졌습니다!!!
시동이 일발입니다!!!
밟으면 가속이 잘됩니다!!!

ㅋㅋㅋ 아주 만족스러운 DIY였습니다. 

물론 이 작업하고 에어컨이 잘 되길 바랬던 나의 무지함은 나중에 온도조절 스위치의 케이블이 느슨해 져서 벌어진 일임을 알아내어 뺀지로 늘어진 케이블을 조여서 해결 했습니다.

이제 오일 갈면서 튜티맞추면 한동안 손댈일 없을 것 같습니다.


P.S :
1. 스로틀밸스, 기화기 등을 청소할때 액상이든 거품식이든 스프레이를 쓰시죠? 청소후에는 꼭  시운전을 하셔서 (20~30Km를 주해 하시고... 시속 100km이상으로 달려주면 깔끔하게 날라가는 듯)  내부에 있는 청소액을 제거 하도록 하세요... 대충 정차상태에서 RPM 올려서 뺀다고 해도 운나쁘게 남아 있는 경우 다음날 와이프가 차 끌고 나가서 신호 대기 하다가 차 시동꺼지는 현상이 발생 합니다. (내부에 청소액이 남아서 시동이 안걸림...이걸 계속 시동을 걸다가 배터리 나가면 ..... 렉카 부르는 겁니다...)

2. 볼트를 조일때 토크
무조건 꽉 조이는게 능사가 아닙니다. 특히나 엔진부품 부분은 알미늉 재질로 된 부분을 힘줘서 조이다가 빠가를 내는 순간 돈 엄청 깨집니다.  스파크 플러그, 수온센서, 써머스텟은 적정한 토크로 조여 주세요 초기 분해시 위치를 표시했다가 그만큼만 조이는것이 방법중 하나입니다. 특히 써머스텟은 위 아래가 있어서 잘못 끼우고 조이다가는 커버가 작살 납니다.

3. 냉각수의 위험성
냉각수는 극유독성 물질입니다. 이거 조금만 먹어도 사람 즉사합니다.(TV 뉴스 보셨죠?  컵라면 물로 끓여 먹었다가 몇명이 한꺼번에 죽은....) 그만큼 환경오염이 심하기 때문에 꼭 카센터에 가서 처리해야 합니다. 저는 냉각수를 뺄때 큰 대야를 놓고 받고 그 아래에 패이퍼 타월을 깔아서 바닦에 흘리지 않도 했고록 뺀 냉각수는 오일통에 넣어서 카센터에 가져가서 처리 했습니다.  절대 냉각수를 쉽게 보지 마시고 정해진 대로 처리하시고  손에 묻거나 눈에 튀지않도록 조심해서 작업해야 합니다.  처리 방법을 모르겠으면 되도록 냉각수 계통은 손을 대지 않도록 하는것을 권합니다.

4. ECU 리셋
차에는 ECU라는 장비가 있습니다. 각종센서의 정보를 사용해서 연료공급 RPM등을 제어합니다.  청소나 부품 교환후에는 평소 입력 값들이 변경되기 때문에 ECU를 초기화 해서 학습정보(?)를 다시 셋팅하도록 해야 합니다. ECU 초기화 하는 방법은 베터리 - 단자를 탈거하거나  휴즈박스에서 ECU 부분의 휴즈를 빼고 5분 정도 방치하고 다시 연결 하면 됩니다.
ECU를 초기화 하고나면 입력정보를 처음부터 수집하기 때문에 카렌스의 경우 계기판의 OverDrive 램프(OD 램프)가 점멸되거나 하기도 합니다.  (OD가 점멸 하는 몇가지 이유중 입력 데이터가 기존 데이터와 다르면 점멸됨..이때 기어가 4단 이상으로 올라가지 않거나..뭐 이상한 증상들이 보인다고 합니다.)
초기값에서 학습하는동안 점멸은 상관없으나(어느정도 운전자의 운전패턴을 인식하면 점멸하지 않습니다.)  한동안 끌고 다녀도 OD가 점멸하는경우  ECU 리셋이 안된경우 일 수 있으니 리셋을 다시 해보고 그래도 이상하면 카센터로 gogo 하세요 

5. Duty 조정
이건 뭐랄까....연료의 공급량을 조정하는건데요...  
듀티 조정은 기화기의 미세조정밸드를 돌려서 하는데.... 큰 수리나 작업 후에는 조정을 해서 맞추는 것이 바람직합니다.
ECU는 배기쪽에 설치된 산소센서에서 배기가스를 측정하여 적절하게 연소되도록 연료유입량을 조정합니다.
듀티가 너무 치우치게 조정되어 연료가 너무 적거나 너무 많이 들어가도록 조정 되면 안됩니다.  엔진 과열 또는 시동꺼짐등의 문제가 발생 할 수 있습니다.
듀티를 시동 상태에서 중립이나 P로 해놓고 적절할 소리를 들어가면서 조정한다고 하는데....글쎄요 100%의 비율중에 50% 수준을 잡아 놓아야  정차 에서 고속 주행 구간의 중간쯤에서 값을 잡아 줘야 하는데 저는 귀나눈으로 맞추기는 힘들 것 같습니다.
되도록 센터에가서 조정을 요청하시고   조정시 비용을 요청 하는 경우가 있는데 단골 센터나  오일이나 다른 부분을 수리하면서 요청 하면 무료로 해주기도 하니  참고하시기 바랍니다. 

자꾸 까먹는 Mongodb 명령어

DB 정지 (데몬을 내리는 방법)
>use admin;
>db.shutdownServer();
DB 확인
> show dbs
DB 사용하기
>use logdb
collection 만들기
>db.createCollection("weblogcoll");
collection 이름 바꾸기
>db.weblogcoll.renaeCollection("newcoll");
collection확인
>show collections
collection 상태 확인
>db.weblogcoll.validate();
collection 날리기
>db.weblogcoll.drop();

> db.weblogColl.remove() 몽땅 삭제
갯수카운트
> db.weblogcoll.find().count();
DB 리페어(파일 단편화나 복구시 사용)
 >db.repairDatabase()   
compact 작업
db.runCommand ( { compact: '<collection>', paddingFactor: 1.1 } )
db.runCommand ( { compact: 'weblogcoll', paddingFactor: 1.1 } )
!! paddingfactor 는 실 데이터 저장공간에 추가로 얼마나 더 먼저 말들어놓을 것이냐는것
연산공식은
padding size = (paddingFactor - 1) * <document size>.
이므로 1.1을 하면 10%를 추가로 만들어놓는것이다. 최대 4 까지 만들 수 있다.
mongodb Export 방법
#mongoexport -d logdb -c weblogcoll -o log.csv
connected to: 127.0.0.1
exported 666277 records
mongodb Import 방법
#mongoimport -d logdb -c weblogcoll  log.csv
connected to: 127.0.0.1
Tue May 07 15:29:11.000                 Progress: 22548226/364820299    6%
Tue May 07 15:29:11.001                         41300   13766/second
Tue May 07 15:29:14.003                 Progress: 55367679/364820299    15%
Tue May 07 15:29:14.004                         101700  16950/second
....
Tue May 07 15:29:42.866 check 9 666277
Tue May 07 15:29:50.106 imported 666277 objects


===============
 인덱스 종류
유니크 인덱스
db.collection.ensureIndex( { a: 1 }, { unique: true } )
non 유니크 인덱스
db.log_system_weblog.ensureIndex({host:1})
db.log_system_weblog.ensureIndex({date:1})
db.log_system_weblog.ensureIndex({file:1})
db.weblogcoll.ensureIndex({agent:1})
인덱스조회
 db.log_system_weblog.getIndexes()

=====================
조회시 조건  rdb like 

db.weblogcoll.find({host : "183.98.13.131"})
db.weblogcoll.find({host : "183.98.13.131"}).sort({time : -1})  시간역순소팅
db.weblogcoll.find({host : "183.98.13.131"}).sort({date:-1},{time : -1})  날짜소팅 후 시간 소팅
db.weblogcoll.find({host : /^119/}) 119로 시작하는 모든 문자열
db.weblogcoll.find({host : /119/}) 119가 들어있는 모든 문자열
db.weblogcoll.find({host : {$not : /119/}}) 119를 제외한 모든 문자열 

Apache Access Log + Mongo DB + Sigma.js

Apache access log를 뭔가??? 비줠 하게 표현하는 ...
이건 해놓기는 했는데 뭔지 좀 병맛이 나......

1. Apache Access Log를 Mongo DB에 넣는다 (ETL 과정)
ETL어떻게 손으로 하나...꽁짜 ETL로 돌립니다.
Talend Open Studio 라는 녀석입니다. (for bigdata 버젼을 받으면  mongodb, hadoop Adapter 들이 제공됩니다.


대충 웹서버 1시간 로그를 15대에서 줏어와서 밀어넣으니 9000만건 정도 들어가내요


2. MapReduce로 MongnDB에서 IP기준으로 이런 저런 데이터를 뽑아봅다.

- 브라우져 점유울 높은놈  MR 하기 
var map_function = function() {
 var key = this.agent;

 if(key != null){
     if(key.indexOf("MSIE") > -1){
        if(key.indexOf("compatible; MSIE 5.0") > -1){
        key = "IE5_";
        }else if(key.indexOf("compatible; MSIE 9.0") > -1 || key.indexOf("compatible; 9.0") > -1){
        key = "IE9_";
        }else if(key.indexOf("compatible; MSIE 10.0") > -1 || key.indexOf("compatible; 10.0") > -1){
        key = "IE10_";
        }else if(key.indexOf("compatible; MSIE 8.0") > -1 || key.indexOf("compatible; 8.0") > -1){
        key = "IE8_";
        }else if(key.indexOf("compatible; MSIE 6.0") > -1 || key.indexOf("compatible; 6.0") > -1){
        key = "IE6_";
        }else if(key.indexOf("compatible; MSIE 7.0") > -1 || key.indexOf("compatible; 7.0") > -1){
        key = "IE7_";
        }else if(key.indexOf("compatible; MSIE 7.7") > -1 || key.indexOf("compatible; 7.7") > -1){
        key = "IE Mobile 7.7_";
        }else{
        key = "IE_etc_";
        }
    }else if(key.toLowerCase().indexOf("winhttp") > -1){
    key = "WinHttp Application_";
    }else if(key.indexOf("Firefox") > -1){
    key = "Firefox_";
     }else if(key.indexOf("Chrome") > -1){
    key = "Chrome_";
     }else if(key.indexOf("Opera") > -1){
    key = "Opera_";
      }else if(key.indexOf("Chrome") < 0 && key.indexOf("Safari") > -1 ){
    key = "Safari_";
      }else if(key.indexOf("Macintosh") > -1 || key.indexOf("iPad") > -1 || key.indexOf("iPhone") > -1){
    key = "Safari_";
     }else if(key.indexOf("Android") > -1){
    key = "Android_";
     }else if(key.indexOf("Java") > -1){
    key = "Java Application_";
     }else if(key.indexOf("Python") > -1){
    key = "Python Application_";
     }else if(key.indexOf("Snoopy") > -1){
    key = "PHP Snoopy Application_";
     }else if(key.indexOf("CoolNovo") > -1){
    key = "CoolNovo_";
     }else if(key.indexOf("Apache") > -1 || key.indexOf("Jakarta") > -1){
    key = "Java HttpClient Application_";
     }else if(key.indexOf("CFNetwork") > -1){
    key = "CFNetwork Application_";
     }else if(key.toLowerCase().indexOf("bot") > -1){
    key = "Bot Crawler_";
     }else if(key.indexOf("Embedly") > -1){
    key = "Embedly Application_";
     }else if(key.indexOf("AdobeAIR") > -1){
    key = "AdobeAIR_";
     }else if(key.indexOf("Flash") > -1){
    key = "Shockwave Flash_";
     }else if(key.indexOf("-") > -1 || key == "null"){
    key = "Bad User Agent_";
    }else{
    key = "etc";
    }
  }
  var value ={count:1};
  emit(key,value);
};

var reduce_function = function(key,value){
  var reduceObj = {
             count:0
             };
  value.forEach(function(value){
    reduceObj.count += value.count;
    }
  );
 
    return reduceObj;
};


db.log_system_weblog.mapReduce(
  map_function,
  reduce_function,
  {
  out : {replace : "mr_system_agent", db : "mrdb"},
  query : {date:{ $gt: "2013-05-13 13:00:00", $lt: "2013-05-13 13:59:00" }}
  }
);

- IP별로 전채 송수신 바이트, 응답시간의총합, 평균응답시간, 호출수 를 구한다. 
// map으로 사용할 데이터를 지정한다.
var map_function = function() {
 var key = this.host;
 var value ={
             hostip : this.host,
             bytes:this.bytes,
             resptime:this.resptime,
             count:1
             };
emit(key,value);
};
//reduce 할 객체를 지정하고 각 항목에 값을 연산하여 집어 넣는다.
var reduce_function = function(key,value){
  var reduceObj = {
             hostip : key,
             bytes:0,
             resptime:0,
             respavg:0,
             count:0
             };
  value.forEach(function(value){
    reduceObj.bytes += value.bytes;
    reduceObj.resptime += value.resptime;
    reduceObj.count += value.count;
    }
  );
    return reduceObj;
};
//다 들어갔으면 평균값 연산을 위하여 final 작업을 하여 집어 넣는다.
var finalize_function = function(key,value){
  if(value.count > 0){
    value.respavg = value.resptime / value.count;
  }
 return value;
};
//MR을 수행한다. 이때 MR 조건은 여기다가 query로 지정한다.
db.log_system_weblog.mapReduce(
  map_function,
  reduce_function,
  { out : "mr_system_weblog",
    query :  {host:{$ne:null}},
    finalize : finalize_function
  }
 );
다른DB에 쓰쓸 경우 아래 참고
db.log_system_weblog.mapReduce(
  map_function,
  reduce_function,
  {
  out : {replace : "mr_system_weblog", db : "mrdb"},
  query : {date:{ $gt: "2013-05-13 13:00:00", $lt: "2013-05-13 13:05:00" }},
  finalize : finalize_function
  }
);
/////////20130530 작업버젼
IP별로 전송용량, 응답시간평균, IP가 Access한 URL List 전체를 포함한 MR collection을 만든다.
수행할때 마다 기존의 Collection은 Replace(제거후생성)한다.
db는 별도 DB에 생성됨
var map_function = function() {
 var key = this.host;
 var value ={
             hostip:this.host,
             bytes:this.bytes,
             resptime:this.resptime,
             url:this.file,
             count:1
             };
emit(key,value);
};

var reduce_function = function(key,value){
  var reduceObj = {
             hostip : key,
             bytes:0,
             resptime:0,
             respavg:0,
             url : "",
             count:0
             };
  value.forEach(function(value){
    reduceObj.bytes += value.bytes;
    reduceObj.resptime += value.resptime;
    reduceObj.count += value.count;
    reduceObj.url += ","+value.url;
    }
  );
 
    return reduceObj;
};
var finalize_function = function(key,value){
  if(value.count > 0){
    value.respavg = value.resptime / value.count;
  }
  if(value.count > 1){
      value.url = value.url.substring(1);
    }
 return value;
};
db.log_system_weblog.mapReduce(
  map_function,
  reduce_function,
  {
  out : {replace : "mr_system_weblog", db : "mrdb"},
  query : {date:{ $gt: "2013-05-13 13:00:00", $lt: "2013-05-13 13:59:00" }},
  finalize : finalize_function
  }
);
===============
shard 환경에서  출력만들때

db.log_system_weblog.mapReduce(
  map_function,
  reduce_function,
  {
  out : {replace : "mr_system_weblog", db : "mrdb", sharded : true},
  query : {date:{ $gt: "2013-05-13 13:00:00", $lt: "2013-05-13 13:59:00" }},
  finalize : finalize_function
  }
);

3. 이걸 비줠하게 표현하기 위해서 나는 gefx 파일 포멧으로 생성 했음

private static void makeTopProductGexf(AggregationOutput output) {
System.out.println("make GEXF");
 
//XML 구조를 생성한다.
// 파일 만들기
Gexf gexf = new GexfImpl();
Calendar date = Calendar.getInstance();
//gexf.setVariant("xmlns=\"http://www.gephi.org/gexf\"");
//확장 Namespace를 사용하기 위해서는 gexf.setVisualization(true); 을 해야 NS를 조회한다.
gexf.setVisualization(true);
gexf.getMetadata()
.setLastModified(date.getTime())
.setCreator("kwon")
.setDescription("Web Traffic Relation");


Graph graph = gexf.getGraph();
graph.
setDefaultEdgeType(EdgeType.UNDIRECTED)
.setMode(Mode.DYNAMIC)
.setTimeType(TimeFormat.XSDDATETIME);
AttributeList attrList = new AttributeListImpl(AttributeClass.NODE);
graph.getAttributeLists().add(attrList);
Attribute attUrl = attrList.createAttribute("URL", AttributeType.STRING, "url");
Attribute attCount = attrList.createAttribute("request cnt", AttributeType.INTEGER, "count")
.setDefaultValue("true");
// 출력결과를 돌리면서 노드를 생성한다.
Iterator<DBObject> it = output.results().iterator();
int cnt = 0;
Color color0 = new ColorImpl(255,51,51);
Color color1 = new ColorImpl(102,255,102);
Color color2 = new ColorImpl(255,153,153);
Color color3 = new ColorImpl(153,255,255);
Color color4 = new ColorImpl(153,255,0);
float size;
while(it.hasNext()){
DBObject obj = it.next();
String url = obj.get("_id").toString();
String count = obj.get("count").toString();
// 제품 번호 없는 놈은 패스
int idx = url.indexOf("prdNo");
if( idx < 0 ){
continue;
}
/* idx = url.indexOf("prdNo=");
if(idx > -1){
url = url.substring(idx);
idx = url.indexOf("&");
// prdno 뒤 잘라내기
if(idx > -1){
url= url.substring(0, idx);
}
// = 짤라내기
idx = url.indexOf("=");
if(idx > -1){
url= url.substring(idx+1);
}
}*/
//System.out.println("url: "+url + "count : "+count);
Node  node = graph.createNode(String.valueOf(cnt));
node.setLabel(url);
node.getAttributeValues().addValue(attUrl, url);
node.getAttributeValues().addValue(attCount, count);
// 한개의 노드 사이즈를 호출한 양에 따라 다르게 표현한다.
size = Float.parseFloat(count)/10;
node.setSize(size);
// 사이즈 군에 따라 색을 통일 지어 표현한다.
if(size < 0.5){
node.setColor(color3);
}else if(size < 1){
node.setColor(color2);
}else if(size < 1.5){
node.setColor(color1);
}else{
node.setColor(color4);
}
cnt++;
}
String filename = "topproduct.xml";
try {
writeXml(gexf,filename);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

4. 이녀석을 sigma.js로 불러서 읽어 들이면 대략 이렇게 나옴


sigma.js 에서 읽어들이는 html 코드는 아래

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>web Relation</title>
  <link rel="stylesheet" href="/css/bootstrap.min.css">
  <link rel="stylesheet" href="/css/bootstrap-responsive.min.css">
  <link rel="stylesheet" href="/css/style.css">
  <link rel="stylesheet" href="/css/prettify.css">
  
<script type="text/javascript" src="js/sigma.min.js"></script>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/sigma.parseGexf.js"></script>

<script type="text/javascript">

function init() {
 // Instanciate sigma.js and customize rendering :
 var sigInst = sigma.init(document.getElementById('sigma-example')).drawingProperties({
   defaultLabelColor: '#fff',
   defaultLabelSize: 14,
   defaultLabelBGColor: '#fff',
   defaultLabelHoverColor: '#000',
   labelThreshold: 6,
   defaultEdgeType: 'curve'
 }).graphProperties({
   minNodeSize: 0.5,
   maxNodeSize: 15,
   minEdgeSize: 1,
   maxEdgeSize: 1
 }).mouseProperties({
   maxRatio: 32
 });
 
 // Parse a GEXF encoded file to fill the graph
 // (requires "sigma.parseGexf.js" to be included)
 //sigInst.parseGexf('/data/arctic.gexf');
 //sigInst.parseGexf('data/arctic.xml');
 //sigInst.parseGexf('data/topip.xml');
 sigInst.parseGexf('data/topproduct.xml');
 // Draw the graph :
 sigInst.draw();

// 속성 출력 스크립트
 /**
   * Now, here is the code that shows the popup :
   */
  (function(){
    var popUp;
    // This function is used to generate the attributes list from the node attributes.
    // Since the graph comes from GEXF, the attibutes look like:
    // [
    //   { attr: 'Lorem', val: '42' },
    //   { attr: 'Ipsum', val: 'dolores' },
    //   ...
    //   { attr: 'Sit',   val: 'amet' }
    // ]
    function attributesToString(attr) {
      return '<ul>' +
        attr.map(function(o){
          return '<li>' + o.attr + ' : ' + o.val + '</li>';
        }).join('') +
        '</ul>';
    }
    function showNodeInfo(event) {
    //alert("야!!!!!")
      popUp && popUp.remove();
      var node;
      sigInst.iterNodes(function(n){
        node = n;
      },[event.content[0]]);
      //alert("1")
     popUp = $(
        '<div class="node-info-popup"></div>'
      ).append(
        // The GEXF parser stores all the attributes in an array named
        // 'attributes'. And since sigma.js does not recognize the key
        // 'attributes' (unlike the keys 'label', 'color', 'size' etc),
        // it stores it in the node 'attr' object :
        attributesToString( node['attr']['attributes'] )
      ).attr(
        'id',
        'node-info'+sigInst.getID()
      ).css({
        'display': 'inline-block',
        'border-radius': 3,
        'padding': 5,
        'background': '#fff',
        'color': '#000',
        'box-shadow': '0 0 4px #666',
        'position': 'absolute',
        'left': node.displayX,
        'top': node.displayY+15
      });
      //alert("2")
      $('ul',popUp).css('margin','0 0 0 20px');
       
      $('#sigma-example').append(popUp);
    }
    function hideNodeInfo(event) {
      popUp && popUp.remove();
      popUp = false;
    }
    sigInst.bind('overnodes',showNodeInfo).bind('outnodes',hideNodeInfo).draw();
  })();
}

if (document.addEventListener) {
 document.addEventListener("DOMContentLoaded", init, false);
} else {
 window.onload = init;
 alert('지원되지 않습니다.') 
}
</script>
<style type="text/css">
  /* sigma.js context : */
  .sigma-parent {
    position: relative;
    border-radius: 4px;
    -moz-border-radius: 4px;
    -webkit-border-radius: 4px;
    background: #222;
    height: 650px;
  }
  .sigma-expand {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
  }
  .buttons-container{
    padding-bottom: 8px;
    padding-top: 12px;
  }
</style>
</head>
<body>
<h1>Web Traffic Relation diagram-Top 100 Product</h1>
  <div class="span12 sigma-parent" id="sigma-example-parent">
    <div class="sigma-expand" id="sigma-example"></div>
  </div>

</body>
</html>