ⓜⓨ ⓢⓣⓞⓡⓨ - 해당되는 글 90건

오늘 자정 런던 웰블리스타디움에서 맨체스터유나이티드(이하 맨유)와 토트넘 결승전이 벌어진다..

올해 클럽월드컵(우승 확정), 프리미어리그, FA컵, 챔피언스리그, 칼링컵까지 5관왕을 노리고 있는 맨유가

5관왕중 하나의 타이틀인 칼링컵결승전이 잠시 후 자정에 벌어지는 것이다....

결승전에 앞서 퍼거슨 감독은 이번 경기는 젊은선수들을 주축으로 포진시켜 경기를 진할 계획을

밝힌바 있다... (참고기사 : "맨유 퍼거슨 "칼링컵 결승은 영건들에게" )

젊은 선수 중 대표적인 선수로는 대런 깁슨, 대니 웹벡, 벤 포스터로 뽑히고 조니 에반스는 부상이 완화되면

나올것으로 예상된다... 이 외에도 포제봉, 파비우도 가능성이 있어 보인다....

과연 우리 박지성은 어떻게 될것인가....? 아무래도 얼마전 챔피언스리그에서 활약한 뒤의 피로와 다음
경기인 5일 뉴캐슬과의 경기가 있어 체력안배를 위해 빼지 않을까 나름 예상
을 해본다...

칼링컵 결승은 23시 55분부터 KBSN에서 중계한다

|


친구와 약속을 잡을때, 회식장소를 공지할때, 온라인 지도를 이용해 길을 알려줄때 등 온라인 지도 사용시,

재미있는 영상이나 게시글, 이슈화되는 뉴스기사들 등의 여러 웹페이지 이용시

인터넷에 있는 이쁜 아가씨 사진, 멋진 남성의 사진, 웃긴 엽기 사진을 보고있을때

가끔 이런거를 사용할때, 아... 누구한테 보여주고 싶은데... 전화해서 애기한다...

"야 xx들어가서 yy검색해서 몇번째꺼에 뭐 클릭해봐" -_-;; 뭐라는겨

또는 메신저에서 링크를 보내주면 쪽지창이 가득찰때도 있다...요즘 메신저 사기도 많아서 스팸이 아닌가

의심해보기도 한다...

이제 이런걱정을 안해도 된다...

드디어 한국에서도 최초로 긴~ url주소를 짧게 만들어 주는 서비스가 나왔다!!!

그이름은 durl ~ 한타로 치게되면 '여기'가 된다... 여기에 접속해보란 뜻인가? 암튼 뜻은 좋다 ^^

한번 들어가 보자 ( http://durl.kr ) 주소마저도 짧다 ㅋ

사용자 삽입 이미지

너무 심플해서 놀라셧나? 캡쳐가 크게 됐지만 저게 첫페이지에 전부다 ㅎㅎㅎ

'Enter a long URL' 텍스트 박스에 긴 url을 입력하면 된다... 그리고 Make it short 버튼을 클릭하면

입력한 긴~ URL을 짧게 만들어 준다... 결과 페이지는?? 아래를 보라~


사용자 삽입 이미지

원래 입력한 주소와 짧아진 주소, 웹페이지의 title, 웹페이지의 상태까지 나온다!!!! 우왓~~~~~~

결과 페이지에서 Original URL 글자와 주소, short url 글자와 주소 모두 클릭하면 해당 주소가 포커스싱이

된다...
사용자를 위한 배려 짱이다~ ㅋㅋ

미리보기 웹페이지 그림은 클릭하게되면 새창으로 웹페이가 연결이 되고 아래에는 다른 url로 다시

해볼수도 있다.. 무려 188개의 URL 글자수가 18개로 확~ 줄었다....

문자 메세지로도 가뿐하게 보낼수 있는 길이다 ... 내가 보내준사람은 어떻게 보냐고? 밑을 보자



사용자 삽입 이미지

웹페이지 title과 미리보기 이미지, Proceed 버튼이 있다...

여기서 Tip title과 Proceed 버튼을 클릭하면 현재창이 바뀌고 이미지를 클릭하면 새창이 뜬다

새창 싫어하시는 분들은 숙지하길 바란다~~~

참고로 세계에 url을 짧게 해주는 서비스는 많은데 한국은 처음으로 알고있고 플레쉬까지 이미지로 잡아

내는 사이트는 몇없는 것으로 안다
한번들 써보시라~~

참!!! 아직 Beta 서비스 중이니 버그나 오류사항이 있으면 나한테 댓글로 신고하면 적극 들어(?) 주겠당~
|
0 : 0

한편의 빠른 액션영화를 본듯한 느낌

경기진행은 이탈리아라고 믿기지 않을만큼 빠르고 숨막히는 속도의 경기였다..

이탈리아 리그 1위 인터밀란!!!
잉글랜트 리그 1위 맨체스터 유나이티드!!!

두팀의 현재 리그 상황만봐도 경기가 얼마나 흥미진진한지 알 수 있는 경기이다...

밀라노(인터밀란 홈)에서 열린경기는 호세 무링요감독과 퍼거슨감독과의 재회로도 많은 관심을 모았는데

여우 무링요감독 언론플레이에도 덤덤한 곰 퍼거슨감독 경기결과는 막상막하 0:0으로 마무리 지었다.



인터밀란
GK : 줄리우 세자르
DF : 이반 코르도바(교체 이전엔 누구였지.. -_-), 마이콘, 크리스티안 키부, 다비데 산톤
MF : 하비에르 사네티, 데얀 스탄코비치, 에스테반 캄비아소, 설리 문타리
FW : 즐라탄 이브라히모비치, 아드리아누

맨유
GK : 에드윈 판 데르사르
DF : 리오 퍼디낸드, 파트리스 에브라, 존 오셰, 조니 에반스
MF : 박지성, 크리스티아누 호날두, 라이언 긱스, 마이클 캐릭, 대런 플래처
FW : 웨인 루니, 디미타르 베르바토프

지난 프리미어리그 블랙번전에 명단제외를 하면서 배려했던 박지성과 반데사르 모두 출전하였다.

전반 초반은 다소 긴장한듯한 선수들이 잦은 실수도 나왔으며 긴장감이 맴도는 경기를 진행했다...

박지성은 경기중반까지 한두번의 실수를 제외하면 크게 결점없는 경기를 해내갔다...

전반 15분경의 수비의 발을 맞은 베르바토프의 패스가 연결됐다면 챔스 2호골을 노려볼만큼

좋은 찬스였다...

역시 양팀 경기의 키플레이어는 호날두이브라히모비치가 이끌어다...

전반 중반으로 갈 수록 맨유의 우세가 더해갔다... 인터밀란의 미드필드 경기진행을 제외하고는 대부분

맨유의 일방적인 공격!!! 역시 최근 최고의 컨디션을 보이는 줄리우 세자르 -_- 너무 잘 막았다

전반끝날때까지 비디치의 공백때문일까 한두번의 맨유의 위기가 있었다

전반은 0:0으로 마무리 정신없는 45분이 흘러갔다...

경기 후반 인터밀란은 홈에서 질 수 없어서일까 다소 공세적으로 나왔다..

전반에 맨유가 일방적인 경기였다고 하면 후반 중반까지는 인터밀란이 밀어 붙히기 시작했다

다행히도 에반스와 퍼디낸드가 감각을 찾으면서 나름 안정적인 수비를 보여줬고 몇번 골 위기도 있었지만

침착하게 대처하여 실점을 막을 수 있었다...

맨유는 원정에서 비기기 작전이였을까? 후반 38분 박지성과 루니를 교체했지만 승리를 위한 교체였다면

너무 늦은 교체가 아니였나 하는 판단
도 있었다... 경기 후반 베르바의 개념없는 경기적응공격자원의

부족으로 맨유는 골을 넣는데는 실패
했다...

후반 종반 긱스의 좋은 찬스가 있었지만 긱스는 슛을 연결하지 못했고

예전의 긱스를 생각할때 경기중 손꼽히게 아쉬운 장면이였다...

이대로 끝나는구나 했을때 역시 호나우도!!! 추가시간도 끝나고 얻은 골문앞 약 20미터 지점에서 프리킥

프리킥이 끝나면 휘슬이 울릴 분위기에서 호날두의 무회전킥!!! 골키퍼가 막았다기 보다는 골키퍼에

맞았다... 아쉽게도 수비가 걷어내는 순간 경기는 종료 되었고 맨유로써는 만족할만한 원정 무승부

만들고 3월 12일 4시 40분 올드트래포드에서 16강 2차전을 진행하게 된다...

엥 -_-;; 그러고보니 맨유는 올드트래포드에서 최소한 이겨야되고 1점이라도 실점하고 비기게 되면

탈락하게 된다... 물론 그런일은 없어야겠지만 8강경기를 맨유경기로 보고싶다~

p.s 챔스경기는 주말에 좀 이른시간에 해달라~ 직장인들 죽겠다 ㅜㅜ

|
생일 : 2008년 1월 8일(음력 12월 13일)
집주소 : 서울특별시 마포구 상수도 72-1 홍익대학교 홍문관 14층 다음커뮤니케이션
신발사이즈 : 270mm
허리사이즈 : 32~33


1. 온라인 상품권(역시 Ver 2에도 유효한 상품권 ㅋㅋ
사용자 삽입 이미지

디앤샵상품권

제일 문안한 선물이죠 ㅋㅋㅋ 10만원권을 바라는건 아니지만 요즘 힘들다 보니 ㅋㅋㅋ


2, 전자레인지
사용자 삽입 이미지

http://www.gmarket.co.kr/challenge/neo_affiliate/daum/daum_redirect.asp?goodscode=150524510&GoodsSale=Y&jaehuid=200002243

다른상품은 아래..
http://shopping.daum.net/product/searchresult.daum?nil_suggest=btn&q=%C0%FC%C0%DA%B7%A3%C1%F6&srchhow=Aexpo

전자레인지.....살림하는데 정말 필요하더라구요 ㅜ.ㅜ 맨날 남는 음식때문에 걱정을 덜어버리고 싶어~


3. 운동화

EXR
사용자 삽입 이미지
http://daum.lotte.com/lotte/sitemap/goods/LCCategoryGoods.jsp?curGoodsNo=6473905&curDispNo=045011&orgDispNo=049011231006&curDepth=#customer


4. 지갑

사용자 삽입 이미지
http://shopping.daum.net/goshop.daum?categoryid=JU021002&masterclick=N&headon=Y&productid=Q50154017&url=http%3A%2F%2Fwww.interpark.com%2Fgate%2Fippgw.jsp%3Fgoods_no%3D103863975%26biz_cd%3DP12782&mall=%C0%CE%C5%CD%C6%C4%C5%A9&&gateyn=N

사용자 삽입 이미지
http://www.dnshop.com/front/product/ProductDetail?CID=D52855&PID=B236_BE8Z9M7095&Sid=DHOW_5N000000_01_00

아..작년에 명함지갑 받았는데요... 주신분 너무 고마워요~ 알랍베베~♡ ㅋ
지갑 바꿀때가 됐드라구요 ㅋㅋㅋ 위에께 더 맘에 들긴하는데 둘다 좋네요- ㅋㅋㅋㅋ
돈 많이 벌어야죠 ㅋㅋㅋ 지갑~

5. 바지
사용자 삽입 이미지

http://shopping.daum.net/goshop.daum?categoryid=GC054&query=%B8%E9%B9%D9%C1%F6&productid=P37922530&url=http%3A%2F%2Fdaum.lotte.com%2Fdaum.jsp%3FcurGoodsNo%3D9051111%26curDispNo%3D045002005021002&mall=&&gateyn=N

사용자 삽입 이미지

http://shopping.daum.net/goshop.daum?categoryid=GC007&query=%B8%E9%B9%D9%C1%F6&productid=G01544480&url=http%3A%2F%2Fwww.interpark.com%2Fgate%2Fippgw.jsp%3Fgoods_no%3D15896136%26biz_cd%3DP12782&mall=&&gateyn=N

사용자 삽입 이미지

http://shopping.daum.net/goshop.daum?categoryid=GC041004&query=&productid=K39952481&url=http%3A%2F%2Fwww.lotteimall.com%2Fservlet%2FLinkServlet%3Fp_id%3D000087%26i_code%3D2080830&mall=&&gateyn=N

이쁘지 않나요? ㅋㅋ 허리는 안전빵으로 33 ㅋㅋ (살빼야 되는데 .. ㅜㅜ)

6. 청소기
사용자 삽입 이미지
http://shopping.daum.net/goshop.daum?categoryid=CE003&masterclick=N&headon=Y&productid=Y14563931&url=http%3A%2F%2Fwww.interpark.com%2Fgate%2Fippgw.jsp%3Fgoods_no%3D56196431%26biz_cd%3DP12782&mall=%C0%CE%C5%CD%C6%C4%C5%A9&&gateyn=N

새로운 내 보금자리를 위해 청소기를 기증해 주세요- ㅋ



생일 : 2008년 1월 8일(음력 12월 13일)
집주소 : 서울특별시 마포구 상수도 72-1 홍익대학교 홍문관 14층 다음커뮤니케이션
신발사이즈 : 270mm
허리사이즈 : 32~33
|

Lucene 2.4가 나오면서 2.4에서의 변화중에 InstantiatedIndex가 나오면서

기존의 RamDirectory Index보다 성능이 향상되었다고 소개한바 있다....

정말 너무너무 반가운 소식이였다.... 얼마전까지 말이다 ㅜㅜ

이런!!!! 이럴수가.... 잘 알고 사용해야 한다. 정말이다.... ㅜㅜ

예~전 lucene에서 indexing할때 Ramdirecory index와 같이 쓰면 좋다라는

식으로 책이나 블로그에 소개가 됐었다...

예를 들면 File Base Index에 직접 쓰는게 아니라 아무래도 속도가 좋은

RamDirectory에 먼저 indexing후 FileIndex에 쓰는 방식을 쓰면 속도가

향상된다고 했지만 2.? 버전에서 방식이 바뀌어 자동으로 이런식으로 인덱싱을

한다고 해서 굳이 RamDirectory로 한번 indexing하는 방식이 필요 없어졌었다

RamDirectory가 사용성이 모호해져서 그런지 향상된 InstantiatedIndex를 내놓았다..

내가 사용한 결과 InstantiatedIndex는 버그가 있었다.

가장 먼저 찾은 버그는 update버그이다. update를 하면 내부적으로 delete후 insert하는

로직을 가졌지만 InstantiatedIndex는 update가 되지 않았다. 그래서 코드에서 delete후

insert 해줬다. 대충 예상해보자면 Ram방식에서는 commit을 해주지 않고 바로

insert하면 적용이 안되는 것이 당연하다(?)ㅋ  버그 리포트가 있겠지

크게 불편하지 않아서 패스~ ㅋㅋ

검색서벌르 만들면서 정말 하고싶었던 플젝을 진행하게 되었는데 Lucene이 도와주질

않다니 ㅜㅜ 아직 정확한 문제점도 찾지 못해서 이후 찾게되면 다시 포스팅 하겠지만

InstantiatedIndex를 사용하면 writer와 reader를 생성가능한데 total doc count를

알 수 있는데 delete를 하더라도 doc count는 줄어들지 않는다 -_-;;

뭐 그냥 카운트니깐라고 생각하고 가볍게 생각했지만 실제 데이터를 지우지 않는 것이

아닌가 하는 의심을 가지게 한다... 아놔...

메모리설정에 문제를 격고 많은 메모리를 설정했지만 어떠한 문제인지 모르지만

엄청나게 인덱싱과 검색이 느려지는 현상이 발생했다.

InstantiatedIndex는 optimize 메소드도 지원하지 않는것이 수상쩍다 ㅜㅜ

아무튼 다시보고 사용하자 InstantiatedIndex !!!

그나마 위로가 되는건 우리 검색 선생님께서 답을 내 주지 않으실까 한다(부담주는거 아니에요~) ㅋㄷㅋㄷ

|

참 제목도 힘들다 -_-;;;

기존에 모두 인덱싱하고 서비스하고 있던 index에 컬럼을 추가해야 되는 일이 생겼다.

ㅜㅜ 그러고 싶지 않았지만 서비스를 해야하기에 어쩔수 없이 일이 생겼다

예를들어 no, name, phone만 사용하던 index에 address라는 컬럼을 추가하게 된것이다.

추가 하는데 무슨일이 생길까? 라는 의문이 생기겠지만 나는 이 새로 추가된 컬럼에

값이 있는것들만 뽑고 싶었다.

Lucene에서 지원하는 ' *:* '라는 검색값을 넣으면 모든 컬럼을 반환해주는것을 내가

사용해야 했기 때문에 의문이 생겨서 테스트를 해보았다.

결과는 어떠할까....

값이
no      name      phone
1         kim         010
2         lee         011
3         park       016

이렇게 있다가 address라는 컬럼을 추가하면서 4  choi   019   pusan 을 넣었다.

no      name      phone    address
1         kim         010
2         lee         011
3         park       016
4         choi       019         pusan

이라고 될것이다. 그럼 검색시에 필드를 address를 설정하고 *:* 라고 하면 어떻게 나올까

정말 나는 뛰어난 Lucene의 힘으로 4에 대한 값만 나왔으면했지만

luke로 테스트 해본결과 1,2,3,4 모두 값이 나왔다 ㅜㅜ

알아서 null이나 인식이 안되는 값을 넣어서 4번만 나오면 얼마나 좋을까....

다들 inexer나 검색서버 운영시에 참고하길 바란다.... 아흑~
|
아 좀 티스토리 잘 좀 되라 힘들다~



공개닷~
|

2008 Daum 신입공채 

21세기 글로벌 미디어 기업을 지향하는  다음(www.daum.net)106일까지

서비스 기획, 마케팅, 개발 등 전분야에 걸쳐 2008년 하반기 신입사원을 모집합니다.

보다 나아진 즐거운 세상을 꿈꾸고, 과감하게 도전할 여러분을 Daum이 기다립니다.

1. 모집부문 및 인원
 - 모집 부문 : 개발, 기획, 영업, 마케팅, 경영관리, 디자인

 - 모집 인원 : 00


2. 전형단계
 - 온라인 입사지원 => 서류심사 => 직무능력테스트 => 인적성 검사 => 1차 직무면접 => 2차 인성면접 => 최종합격

* 서류전형
: 필요 요건 및 직무 경력과 지원 동기를 중점으로 심사

직무능력 테스트 : 직무에 필요한 기본 요건을 테스트 (직무에 따라 과제로 대체 가능)

3. 접수기간
 - 2008916() ~2008106()

4. 접수방법
 - 당사소정양식(온라인지원)
 - Daum
홈페이지 > 인재채용 > Daum 공채
 
- 다음에서 'Daum 신입 공채'를 검색

5. 채용 관련 문의
 - daum_recruit@hanmail.net, daum_recruit@daum.net
|

What is Lucene

Jakarta Lucene은 고성능의 확장 가능한 검색 엔진 기술로서 완전히 자바로 작성되었다. Lucene API는 인덱스 구성에 관한 기능과 검색 기능으로 구성되어 있다. Jakarta Lucene은 텍스트 검색 엔진을 필요로 하는 모든 어플리케이션에 적합한 기술이다.

Lucene의 기본적인 용어와 설명

용어 설명
indexing 인덱싱이란 인덱스를 생성하는 처리 과정이다. 인덱스는 컴파일된 문서들의 버전을 포함하고 있는 특별한 데이터베이스이며, 특정 단어들(term)들을 포함하고 있는 문서 목록을 빠르게 찾을 수 있도록 최적화 되어 있다. 대개 이러한 인덱스들은 선택된 한 디렉토리에 Lucene이 생성한 일련의 파일들에 저장된다.
analyzer Analyzer는 인덱싱 동안 문서의 내용을 어떻게 term(단어들)들로 쪼개야 할지에 대해 제어하는 클래스이다. 예를 들면, 어떤 한 analyzer는 "The ill dogs"라는 텍스트를 소문자로 바꾸어 "the", "ill, dogs"의 형태로 쪼개는 반면, 다른 한 analyzer는 소문자로 변환하고 복수형태는 단수 형태로 정규화 하며 일반적인 단어인 "the"는 제거한 형태인 "ill", "dog"라고 쪼갤 수도 있다. 어떤 analyzer를 사용할지 선택하는 것이 중요하다.
searching 이는 원하는 내용을 포함하고 있는 문서의 일부나 몇몇 지정한 사항들과 일치하는 문서의 속성들을 찾는 과정(operation)이다. search 연산은 미리 컴파일된 문서들을 포함하고 있는 특수한 데이터인 '인덱스'에 대해 수행된다. 인덱스 데이터베이스는 "인덱싱" 과정 동안 생성된다.
query 일반적으로 query는 문서를 선택하기 위한 criteria를 지정하며, searching은 문서 인덱스와 query를 비교하고 query와 일치하는 것들을 찾음으로써 이루어진다. query의 결과로 해당 criteria와 일치하는 문서들의 목록(hits)을 얻게 된다.
document Lucene에서 사용하는 문서를 나타낸다. 문서를 나타내기 위해 Document라는 클래스가 제공된다. 이 클래스의 인스턴스는 인덱싱 과정 동안은 인덱스에 추가될 문서들의 정보를 나타내며 검색 동안은 검색의 명중율(hits)을 나타낸다.
field 문서와 hit 정보는 Document 클래스에 필드들의 목록으로 표현된다. 각각의 필드는 이름(String)과 값(문자열이 추출될 수 있는 String이나 Reader)를 포함하고 있다. 또한 각각의 필드는 세 가지 boolean 속성을 갖는데, 이들의 조합은 인덱싱 동안 필드가 사용되는 방법을 지정한다. 이들 속성은 isIndexed, isStored, isTokenized이다.
hit 이것은 query의 결과이며, 지정된 query와 일치하는 문서들의 목록을 말한다. hit 목록은 일반적으로 ranking이나 scoring라 불리는 몇몇 관련 정도의 단위로 정렬된다. hit 목록에는 질의와 일치하는 문서들(매우 높은 score를 가진 문서들)로 이루어진 것들 중의 일부분만을 포함할 수도 한다.
terms 일반적으로 terms는 단어(words)라고 생각할 수 있다. 예를 들면, 문자열 "yadda yadda yadda"는 세 개의 terms를 포함하고 있으며, 이들 각각의 terms는 "yadda"라는 값을 가지고 있다. Lucene이나 대부분의 검색 엔진에서 terms는 인덱싱과 검색을 위한 기본적인 단위이다. terms 값들은 대소문자를 구별한다. 영어나 라틴 언어가 아닌 다른 언어의 텍스트를 terms들로 쪼갤 필요가 있는 경우 규칙들을 커스터마이징 할 수 있다.
tokenizing 문자열을 terms들로 쪼개는 과정. tokenizing은 Analyzer 객체를 사용해 생성되는 TokenStream의 인스턴스들에 의해 수행된다. 만약 한 문서의 필드가 인덱싱 과정 동안 "tokenize하지 않도록" 지정되었다면, 필드의 전체 내용이 단일 term으로 간주된다(URL인 경우 유용).
term query Lucene에서의 매우 단순한 질의이며 한 단어와 비교하는 경우에 사용된다. TermQuery 클래스로 표현되며 term과 필드 이름을 포함하고 있다.
boost factor query 구조와 일치하는 문서의 랭킹을 증가시키거나 감소시키는데 사용될 수 있는 factor.
phrase query 필드에서 연속된 일련의 terms들에 대해 일치하는지를 비교하는 query를 나타낸다. 예를 들면, "winding road"는 "winding road"와는 일치해야 하지만 "road winding"와는 일치하지 않는다. PhraseQuery 클래스 인스턴스로 표현된다. 이 인스턴스는 일치하는 terms들을 표현하는 정렬된 Term 객체들로 이루어진 리스트를 포함한다.
boolean query "AND", "OR", "NOT"과 같은 규칙들을 사용한 복합 질의를 나타낸다. BooleanQuery 클래스의 인스턴스로 표현된다. 각각의 객체는 BooleanClause라는 어댑터 클래스의 인스턴스를 사용해 연결된 하위 질의들의 목록을 포함하고 있다.
filtering hit 목록에 대해 추가적인 제한을 가해 검색 결과에 영향을 주는 것을 말한다.
 
 
 
 

Lucene의 설치

다운로드 받은 Lucene의 압축을 적절한 디렉토리에 푼 후, lucene-1.4-final.jar를 클래스패스에 추가하면 Lucene의 설치는 끝난다.

주요 클래스 설명

  • 인덱싱 관련 클래스
클래스 이름 설명
IndexWriter 인덱스를 만들고 유지한다. 생성자의 인자들은 위에서 설명한 것과 동일하다. Document들을 추가하는 작업이 종료된 후에는 반드시 이 객체의 close 메소드를 통해 닫아주어야 한다. 만약 잠시 동안 추가될 Document들이 더 이상 없고 검색 성능을 높이기 위한 최적화를 수행하고자 할 경우, close 메소드 호출 전에 optimize 메소드를 호출할 수도 있다.
Analyzer 텍스트를 분석하는 TokenStream들을 만들어준다. 즉, 문서를 인덱싱 하거나 검새갈 때 핵심이 되는 요소로서, 텍스트를 파싱 할 때 사용된다.
StandardAnalyzer 추상 클래스 Analyzer를 구현한 클래스이다. 아스키 코드, 라틴권 문자와 언어 문법을 기반으로 한 analyzer이다. stop word에 대해서는 인덱싱 처리를 하지 않는다.
WhitespaceAnalyzer 추상 클래스 Analyzer를 구현한 클래스이다. 공백 문자를 기준으로 인덱싱 작업을 한다.
SimpleAnalyzer 공백과 하이픈을 사용해 단어를 구분하여 인덱싱 작업을 한다.
Document Document는 한 문서에 대한 정보를 담고 있다. Document는 인덱싱과 검색의 단위이며, 필드들로 이루어져 있다. 각각의 필드는 이름과 텍스트 값을 가지고 있다. 대개 Document는 하나 이상의 stored 필드들을 갖는다.
Field 필드는 Document의 일부를 구성한다. 각각의 필드는 이름과 값이라는 두 가지 부분을 갖는다. 값들은 String이나 Reader로 제공되는 형태의 텍스트나 atomic한 keyword들일 수 있다. 필드들은 선택적으로 인덱스에 저장되어 검색된 문서와 함께 반환될 수 있다. Field에는 Keyword, UnIndexed, UnStored, Text라는 네 가지 타입이 있다.
Field.Text 텍스트 데이터를 토큰으로 구분하여 인덱싱 작업을 수행하며, 그 값을 인덱스에 저장한다.
Field.Keyword 텍스트 데이터를 토큰으로 나누지 않는다. 인덱싱 작업을 처리하며 텍스트 데이터 그대로 인덱스에 저장된다.
Field.UnIndexed 텍스트 데이터를 토큰으로 분리하지 않고, 인덱싱 작업도 처리하지 않는다. 텍스트 데이터는 그대로 저장한다.
Field.UnStored 텍스트 데이터를 토큰으로 분리하고 인덱싱 작업도 처리하지만, 텍스트 데이터는 저장하지 않는다.

  • 검색 관련 클래스
클래스 이름 설명
Searcher 검색 구현을 위한 abstract base 클래스이다. 몇몇 일반적인 유틸리티 메소드들을 구현하고 있다.
IndexSearcher 단일 IndexReader에 대한 검색을 구현한 클래스이다. 어플리케이션에서는 상속된 Searcher.search(Query)나 Searcher.search(Query, Filter) 메소드를 호출한다.
QueryParser 이 클래스는 JavaCC에 의해 생성된다. 클라이언트에서는 parse() 메소드를 호출하게 된다. 이 메소드는 질의 문자열을 파싱 하여 Query를 반환한다.
Query 질의를 위한 abstract base 클래스이다.
Hits 순위가 매겨진 Document들의 목록이며, 검색 결과를 저장하고 유지하는데 사용된다.






Query Syntax

Terms
질의는 term과 연산자(operator)로 나뉜다. term에는 Single terms라는 것과 Phrases라는 두 가지 타입이 term이 존재한다. Single Term은 "test"나 "hello"와 같이 한 단어로 이루어진다. Phrase는 "hello dolly"와 같이 인용 부호로 감싸여진 여러 단어로 이루어진다. 여러 term들은 보다 복잡한 질의를 나타내기 위해 Boolean 연산자와 함께 조합될 수 있다.

Fields
Lucene은 필드화 된 데이터를 지원한다. 검색을 수행할 때, 필드를 지정하거나 디폴트 필드를 사용할 수 있다. 필드 이름들과 디폴트 필드는 구현에 종속적이다. 필드 이름 다음에 콜론(:)을 적고 찾으려는 term을 적어 넣음으로써 어떠한 필드라도 검색할 수 있다.

예를 들면, Lucene 인덱스가 title과 text라는 두 개의 필드를 포함하고 있다고 가정해보자. 이 때 text는 디폴트 필드라고 가정한다. 만약 "don't go this way"라는 text를 포함하며 "The Right Way"라는 title을 갖는 문서를 검색하고자 한다면, 다음 둘 중 한 방식으로 입력하면 된다.

title:"The Right Way" AND text:go 또는 title:"Do it right" AND right 

text는 디폴트 필드이기 때문에 필드 지시어(indicator)는 반드시 입력될 필요가 없다.

필드는 바로 뒤에 따르는 term에 대해서만 유효하기 때문에, title:Do it right라고 질의를 입력하는 경우, 이는 title 필드에서 "Do"만을 찾게 된다. 나머지 "it"과 "right"는 디폴트 필드에서 찾게 된다.

Term Modifiers
Lucene은 보다 광범위한 검색 옵션을 제공하고 있다.

와일드카드 검색

Lucene은 단일 문자 와일드카드 검색과 다수 문자 와일드카드 검색을 지원하고 있다. 단일 문자 와일드카드 검색에서는 "?" 기호를 사용하며, 다수 문자 와일드카드 검색에서는 "*" 기호를 사용한다.

단일 문자 와일드카드 검색의 예: "text"나 "test"를 검색하려면, te?t의 형태로 검색할 수 있다. 다수 문자 와일드카드 검색의 예: "test", "tests", "tester"를 검색하려 한다면, test* 형태로 검색한다. 

와일드카드는 te*t의 형태와 같이 term의 중간에 사용할 수도 있다. 그러나, *나 ? 기호는 검색 첫 글자의 위치에 사용할 수 없다.


Fuzzy 검색

Lucene은 Levenshtein Distance 알고리즘이나 Edit Distance 알고리즘에 기반하여 fuzzy 검색을 지원한다. fuzzy 검색을 수행하려면, Single word Term의 뒤에 틸드 기호인 "~"를 사용한다. 예를 들어, "roam"과 유사한 스펠링을 가진 term을 검색하려는 경우, roam~ 과 같은 형태를 사용한다. 이렇게 검색하게 되면 foam, roams와 같은 term들을 검색하게 된다.


Proximity 검색

Lucene supports finding words are a within a specific distance away. proximity 검색을 수행하려면 Phrase의 뒤에 "~" 기호를 사용한다. 예를 들어, 한 문서 안에서 각각 10 단어 내에서 "apache"와 "jakarta"를 검색하려 한다면 "jakarta apache"~10과 같은 형태로 검색을 수행하면 된다.

Range 검색

Range 질의를 이용하면 필드의 값이 질의에 지정된 범위 내에 있는 값들과 일치하는 문서들을 찾아낼 수 있다. Range 질의에서는 최소값과 최대값을 포함하거나 제외한 검색 결과를 얻을 수 있다. 정렬은 사전 순서로 이루어진다.

 mod_date:[20020101 TO 20030101] 

이것은 20020101과 20030101을 포함하여, 이 범위 안에 있는 값들을 가진 mod_date 필드들을 포함하고 있는 문서를 검색하게 된다. Range 질의는 날짜 필드 검색에만 국한되지 않는다. 다음과 같이 날짜가 아닌 필드들에 대해서도 가능하다.

title:{Aida TO Carmen} 

이것은 Aida와 Carmen 범위 내에 있는 title을 갖는 문서들을 찾는다. 이 때, Aida와 Carmen은 포함되지 않는다.

최소값과 최대값을 포함한 Range 검색은 [ ] 기호를 사용하며, 포함하지 않는 Range 검색은  { } 기호를 사용한다.


Boosting a Term

Lucene은 발견된 term들을 기반으로 문서가 일치하는 정도를 판단하는 기능을 제공한다. term을 boost하려면, 검색하려는 term의 끝에 boost factor (숫자)와 함께 캐럿 기호 "^"를 사용한다. boost factor가 높을수록, term과의 관련성이 더 높아진다.

Boosting을 사용하여 문서의 term을 boosting함으로써, 문서의 관련성을 제어할 수 있다. 예를 들어, jakarta apache를 검색하려 하는데, "jakarta"라는 term이 보다 더 중점을 두어 검색하려 한다면, jakarta4 apache와 같은 형태로 term 다음에 기호와 함께 boost factor를 사용하면 된다.

이는 jakarta라는 term을 가진 문서가 보다 더 연관성이 높은 것으로 만들어준다. "jakarta apache"^4 "jakarta lucene"과 같이 Phrase term에 대해서도 boost할 수 있다.

디폴트로 boost factor는 1이다. boost factor는 반드시 양수여야 하지만, 0.2와 같이 1보다 작을 수는 있다.

Boolean 연산자
Boolean 연산자를 사용하면 논리 연산자를 통해 term들을 조합할 수 있다. Lucene은 AND, "+", OR, NOT, "-"을 Boolean 연산자로 지원한다. Boolean 연산자들은 반드시 대문자여야 한다.

OR
OR 연산자는 디폴트 결합 연산자이다. 즉, 두 term 사이에 어떠한 Boolean 연산자도 존재하지 않는다면, OR 연산자가 사용된다. OR 연산자는 두 term들을 연결하여, 이 term들 중 하나라도 문서에 존재하는지에 대해 검색한다. 이는 합집합 연산과 동일하다. OR라는 단어 대신 기호 ||를 사용할 수도 있다.

"jakarta apache"나 "jakarta"만을 포함하고 있는 문서들을 검색하려면, "jakarta apache" jakarta나 "jakarta apache" OR jakarta와 같은 형태의 질의를 사용하면 된다.

AND
AND 연산자는 두 term을 모두 갖는 문서들을 검색한다. 이는 교집합 연산과 동일하다. AND라는 단어 대신 기호 &&를 사용할 수도 있다.

"jakarta apache"와 "jakarta lucene"을 포함하고 있는 문서들을 검색하려면, "jakarta apache" AND "jakarta lucene"과 같은 형태의 질의를 사용하면 된다.

+
"+"가 표시된 요소는 반드시 포함되어 있어야 한다는 것을 의미한다. "jakarta"는 반드시 포함해야 하며 "lucene"은 포함될 수도 있는 문서들을 검색하려면, +jakarta apache와 같은 형태의 질의를 사용하면 된다.

NOT
NOT 연산자는 NOT 다음에 나온 term을 포함한 문서들은 배제한다. 이는 차집합 연산과 동일하다. NOT 단어 대신 ! 기호를 사용할 수 있다.

"jakarta apache"는 포함하고 있지만 "jakarta lucene"은 포함하지 않는 문서들을 검색하려면, "jakarta apache" NOT "jakarta lucene"과 같은 형태의 질의를 사용하면 된다.

NOT 연산자는 한 term에만 사용될 수 없다. 예를 들면, NOT "jakarta apache"와 같이 사용할 수 없으며, 이는 어떠한 결과도 반환하지 않을 것이다.

-
"-" 연산자는 "-" 기호 다음에 있는 term을 포함하고 있는 문서들은 제외한다. "jakarta apache"는 포함하지만 "jakarta lucene"은 포함하지 않는 문서들을 검색하려면 "jakarta apache" -"jakarta lucene"과 같은 형태의 질의를 사용하면 된다.

Grouping
Lucene에서는 서브 질의를 형성하기 위해 괄호를 사용하여 절들을 묶을 수 있다. 이는 boolean 로직을 제어하려는 경우 유용할 수 있다.

"jakarta" OR "apache" AND "website"를 검색하려면 (jakarta OR apache) AND website라는 형태의 질의를 사용하면 된다.

Field Grouping
Lucene에서는 여러 절들을 하나의 필드로 묶는데 괄호를 사용할 수 있다.

"return"이라는 단어와 "pink panther"이라는 phrase를 모두 포함하고 있는 title을 찾으려면, title:(+return +"pink panther")와 같은 질의를 사용하면 된다.

Escaping Special Characters
Lucene에서는 질의에 특수 문자를 escaping하는 기능을 지원해준다. 이들 특수 문자들은 다음과 같다.

+ - && || ! ( ) { } [ ] ^ " ~ * ? :

이들 특수 문자들을 escape 하려면, 문자 앞에 를 붙인다. 예를 들면, (1+1):2를 검색하려면 (1+1):2와 같은 질의를 사용하면 된다.

관련 아티클 및 자료

Lucene Home http://jakarta.apache.org/lucene/
Lucene FAQ http://lucene.sourceforge.net/cgi-bin/faq/faqmanager.cgi
Lucene Getting Started http://jakarta.apache.org/lucene/docs/gettingstarted.html
고수로 가는 지름길 Jakarta Project 가메출판사 최범균 저
QueryParser Rules http://today.java.net/pub/a/today/2003/11/07/QueryParserRules.html
Give your Web site its own search engine using Lucene http://builder.com.com/5100-6389-5054799.html
Lucene Intro http://today.java.net/pub/a/today/2003/07/30/LuceneIntro.html
Parsing, indexing, and searching XML with Digester and Lucene http://www-106.ibm.com/developerworks/library/j-lucene/
Advanced Text Indexing with Lucene http://www.onjava.com/pub/a/onjava/2003/03/05/lucene.html
Introduction to Text Indexing with Apache Jakarta Lucene http://www.onjava.com/pub/a/onjava/2003/01/15/lucene.html
The Lucene search engine Powerful flexible and free http://www.javaworld.com/javaworld/jw-09-2000/jw-0915-lucene.html

다운로드

Lucene 바이너리 다운로드 http://jakarta.apache.org/site/binindex.cgi
Lucene 소스 다운로드 http://jakarta.apache.org/site/sourceindex.cgi






Lucene 데모 실행

Lucene 배포본을 다운로드 받으면 그 안에 데모가 들어 있다. 여기에서는 이 데모를 실행하는 방법에 대해 살펴보도록 하겠다.

1. 우선 Lucene의 데모를 실행하기 위해서는 압축이 풀린 디렉토리에 있는 lucene-1.4-final.jar 파일과 lucene-demos-1.4-final.jar 파일이 클래스패스에 잡혀 있어야 한다.

2. 인덱스를 생성한다. 데모의 인덱스를 구성하는 어플리케이션의 이름은 IndexFiles로서, 이는 org.apache.lucene.demo 패키지에 들어 있다. 다음 명령을 실행하게 되면 Lucene 배포본의 src라는 하위 디렉토리에 있는 Lucene에 대한 모든 소스 코드를 대상으로 인덱스를 구성하게 된다.
첫 번째 인자는 <Lucene 배포본의 압축을 푼 위치>src의 형태를 취한다.

java org.apache.lucene.demo.IndexFiles C:ApacheJakartalucene-1.4-finalsrc 

다음은 명령 프롬프트에서 클래스패스를 잡고 위 명령어를 실행한 결과 화면이다.




 
 
3. 위 과정이 성공적으로 이루어졌다면 인덱스 생성은 끝나게 된다. 위 예제를 실행 시킨 후 탐색기로 살펴보면 다음 화면과 같은 디렉토리와 파일이 생성된다.
 



 
 
4. 데모에서 생성된 인덱스를 검색하는 클래스는 SearchFiles로, org.apache.lucene.demo 패키지에 들어 있다.

java org.apache.lucene.demo.SearchFiles 

위 명령을 실행하게 되면 질의를 입력하도록 요청 받을 것이다. 여기에서 찾으려는 단어를 입력하고 엔터키를 누르면 검색된 결과를 보여준다. 결과 화면은 10개 단위로 보여주며, 결과를 보여준 후 다음 10개 항목을 볼 것인지 아닌지를 선택할 수 있다. 다음은 java와 vector에 대한 질의 실행 결과를 나타낸 화면이다.

 
 
 
 
 
 
 
 
 

Lucene 데모 소스 코드에 대한 설명

소스 코드의 위치
Lucene의 압축을 풀어 생성된 디렉토리에서 "src"라는 디렉토리에 "demo"라는 디렉토리가 있다. 이 디렉토리는 모든 Lucene 데모에 대한 루트 디렉토리이다. 모든 자바 소스는 이 디렉토리 아래의 org/apache/lucene/demo에 위치해 있다.

Indexing Files
앞에서 말한 디렉토리에 보면 인덱스를 생성하는데 사용된 IndexFiles.java를 볼 수 있을 것이다. 이것이 어떻게 동작하는지 살펴보도록 하자.

이 소스 코드에 있는 main 함수는 가장 먼저 IndexWriter의 인스턴스를 생성한다. 이 인스턴스는 "index"라는 문자열과 "StandardAnalyzer"라는 클래스의 새로운 인스턴스를 넘겨 받는다. "index"는 모든 인덱스 정보가 저장될 디렉토리 이름이다. 이 예제에서는 어떠한 경로 정보도 지정하지 않고 있기 때문에, 현재 디렉토리의 하위 디렉토리에 생성하는 것을 가정하고 있다.

IndexWriter는 인덱스들을 생성하는 역할을 담당하는 클래스이다. 이를 사용하려면, 이 클래스의 인스턴스를 생성할 때, 인덱스를 작성할 수 있는 경로 정보를 넘겨주어야한다. 이 예제의 경우, 이 경로에 인덱스가 존재하지 않는다면, 이를 생성하게 된다. 만약 해당 경로에 인덱스가 존재한다면, 그 인덱스를 갱신하게 된다. 또한, IndexWriter의 인스턴스를 생성할 때 org.apache.analysis.Analyzer의 인스턴스도 넘겨주어야 한다. 다음 코드는 이러한 작업을 수행한다.

IndexWriter writer = new IndexWriter("index", new StandardAnalyzer(), true); 

이 예제에서 사용한 Analyzer인 Stop Analyzer는 모든 문자열들을 소문자로 만들고 인덱스로부터 쓸모 없는(useless) 단어들을 걸러낸다. 여기에서 쓸모 없는 단어란, a, an, the와 같은 관사들과 검색에 필요없는 일반적인 단어들을 의미한다. 각각의 언어마다 서로 다른 규칙들이 존재하고 있다는 사실에 주의하며, 이들 각각의 언어에 적절한 analyzer를 사용해야 한다. Lucene는 현재 영어와 독일어를 위한 Analyzer들을 지원하고 있다.
(한국어, 중국어, 일본어와 같은 아시아권 언어에 대한 analyzer의 경우, Jakarta Lucene의 Sandbox에서 제공되는 analyzer를 사용하면 된다고 한다)

IndexFiles 소스 파일의 아래에 보면 indexDocs()라는 메소드가 있다. 이 메소드는 재귀적인 함수로, 지정한 하위 디렉토리를 돌아다니면서 FileDocument를 사용하여 Document 객체들을 생성한다. Document는 파일의 생성 일자, 위치 및 그 내용을 표현해주는 간단한 데이터 객체이다. 이들 Document의 인스턴스들은 IndexWriter에 추가된다. 다음은 indexDocs() 메소드에 대한 소스 코드이다.

public static void indexDocs(IndexWriter writer, File file) throws IOException { 
if (file.canRead()) {
if (file.isDirectory()) {
String[] files = file.list();
if (files != null) {
for (int i = 0; i < files.length; i++) {
indexDocs(writer, new File(file, files[i]));
}
}
} else {
System.out.println("adding " + file);
try {
writer.addDocument(FileDocument.Document(file));
} catch (FileNotFoundException fnfe) {
}
}
}
}

indexDocs()는 인자로 받은 File을 읽을 수 있는지 판별하고, 이것이 디렉토리인지 파일인지 검사한다. 만약 디렉토리라면 그 하위 디렉토리를 재귀적으로 검사해 나가며, 파일인 경우 IndexWriter의 addDocument() 메소드를 통해 인덱스에 Document를 추가한다. 이 때, addDocument() 메소드는 인자로 Document를 받는데, 이 예제에서는 FileDocument라는 유틸리티 클래스를 사용하고 있다. 이 유틸리티 클래스는 File로부터 Lucene Document 객체를 만들어준다.

FileDocument는 File 객체에 들어 있는 정보를 바탕으로 Document 객체를 만들어준다. Document 객체는 세 개의 필드로 File에 대한 정보를 표현한다. 이들 필드들은 다음과 같다.
  • path: 파일에 대한 경로명. 텍스트 값 저장(Stored), 토큰 처리(Tokenized) 필드이다.
  • modified: 파일의 최종 수정일. org.apache.jakarta.lucene.DateField에 의해 인코딩 된 Keyword 필드이다.
  • contents: 파일의 내용. Reader 필드이다.

Searching Files
SearchFiles는 검색을 수행한다. 이 클래스는 IndexSearcher, StandardAnalyzer, QueryParser와 상호 작용한다.
이 클래스의 main() 메소드에서는 먼저 검색을 수행하는 Searcher의 객체를 생성하고 질의를 분석하는데 사용될 Analyzer 객체를 생성한다. 다음은 이를 수행하는 코드이다.

Searcher searcher = new IndexSearcher("index"); 
Analyzer analyzer = new StandardAnalyzer();

query parser는 Index를 해석할 때 사용했던 analyzer와 동일한 analyzer를 사용한다. 다음 코드는 이러한 작업을 수행한다.

Query query = QueryParser.parse(line, "contents", analyzer); 

Query 객체는 QueryParser로부터의 결과를 포함하고 있는데, 이 Query 객체는 searcher로 넘겨진다. searcher의 결과들은 "Hits"라 불리는 Document들의 컬렉션에 담겨져 반환된다. Query를 지정하기 위한 syntax는 매우 다양하다. 이들에 대한 내용은 아래에서 간단하게 다룰 것이다.

Hits hits = searcher.search(query); 

그런 후, 이들 컬렉션을 순환하면서 그 안의 내용을 사용자에게 보여준다.

for (int start = 0; start < hits.length(); start += HITS_PER_PAGE) { 
int end = Math.min(hits.length(), start + HITS_PER_PAGE);
for (int i = start; i < end; i++) {
Document doc = hits.doc(i);

String path = doc.get("path");
if (path != null) {
System.out.println(i + ". " + path);
} else {
String url = doc.get("url");
if (url != null) {
System.out.println(i + ". " + url);
System.out.println(" - " + doc.get("title"));
} else {
System.out.println(i + ". " + "No path nor URL for this document");
}
}
}

if (hits.length() > end) {
System.out.print("more (y/n) ? ");
line = in.readLine();
if (line.length() == 0 || line.charAt(0) == 'n')
break;
}
}

요약

다음은 일반적으로 Lucene을 standalone 형태의 어플리케이션에서 사용하는 절차를 간단하게 정리한 것이다.

인덱스 만들기
인덱스를 만드는 절차는 다음과 같다.
  • IndexWriter 객체를 생성한다.
이 객체를 생성할 때는 인자로 세 개의 정보를 넘겨준다. 우선 첫 번째 인자는 인덱스를 생성할 경로를 설정한다. 두 번째 인자는 사용할 Analyzer의 인스턴스이다. Analyzer는 Lucene에서 다수 구현하여 제공하고 있다. 세 번째 인자는 기존의 인덱스가 존재한다면 갱신할 것인지, 아니면 다시 새로 만들 것인지에 대해 지정한다. 자세한 내용은 Lucene API 문서를 찾아보길 바란다.
  • 인덱싱 작업의 대상이 되는 경로로부터 디렉토리와 파일 정보를 읽어 들여, 디렉토리인 경우는 재귀적인 호출을 통해 하위 디렉토리까지 검색하도록 하며, 파일인 경우는 필요한 정보를 추출한 후, org.apache.lucene.Document 형태로 구성하고, IndexWriter의 addDocument() 메소드를 통해 이를 추가한다.

검색하기
  • Searcher 객체를 생성한다. 이 객체는 인덱스가 생성되어 있는 경로를 인자로 받아 추후 검색을 수행한다.
  • 분석에 사용할 Analyzer를 생성한다. 이 Analyzer는 인덱스를 생성할 때 사용했던 Analyzer의 종류와 같은 것이어야 한다. 만약 다른 것을 사용한다면 잘못된 검색 결과를 얻을 수 있다.
  • QueryParser의 parse() 메소드를 이용하여 Query 객체를 생성한다. parse() 메소드는 검색어, 인덱스 생성 시 작성했던 필드 명과 위에서 생성한 analyzer 객체를 인자로 받아 인덱스 정보를 검색한다.
  • QueryParser를 통해 얻어진 Query 객체로부터, 검색 결과를 담고 있는 Hits를 얻어온 후, Hits가 담고 있는 내용들을 보여준다.




예제 실행을 위한 절차

Indexing Files
이 단계에서는 웹 어플리케이션 예제에서 필요한 인덱스를 작성하게 된다. 우선은 lucene-1.4-final.jar 파일과 lucene-demos-1.4-final.jar 파일이 클래스패스에 잡혀 있어야 한다. 명령 프롬프트에서 {tomcat-home}/webapps의 하위 디렉토리 중 아무 곳으로나 이동하여 다음 명령어를 실행한다.

java org.apache.lucene.demo.IndexHTML -create -index C:ApacheJakartaTomcat-5.0luceneIndex .. 

이 명령어에서 뒤의 ..을 반드시 입력해야 한다. 그렇지 않으면 예외가 발생한다. 세번째 인자는 Tomcat이 읽고 기록할 수 있지만, 웹을 통해서는 접근이 불가능한 디렉토리이다. 이 디렉토리에는 생성된 인덱스가 저장된다. 데모 웹 어플리케이션에서는 이 위치에서 인덱스를 찾도록 설정하고 있다. 이를 실행하게 되면 톰캣의 webapps 디렉토리의 하위에 있는 모든 디렉토리에 존재하는 문서들에 대한 정보를 담고 있는 인덱스를 생성하여 지정된 인덱스 디렉토리에 작성하게 된다. 여기에서는 luceneIndex가 될 것이다.

다음은 이 명령을 실행한 결과와 앞에서 지정했던 인덱스 디렉토리의 모습을 담은 화면이다.

 




 
Deploying the Demos
Lucene을 다운로드 받아 압축을 푼 디렉토리에 보면 luceneweb.war라는 war 파일을 볼 수 있을 것이다. 이 파일을 {tomcat-home}/webapps 디렉토리로 복사하고 톰캣을 재시작한다. {tomcat-home}은 톰캣이 설치된 디렉토리이다. 이 과정을 마치고 나면 다음처럼 luceneweb이라는 웹 어플리케이션이 생성된 것을 볼 수 있을 것이다.
 


 
 
Configuration
톰캣 디렉토리에서 webapps/luceneweb 하위 디렉토리로 이동한다. 만약 존재하지 않는다면, 브라우저의 주소 창에서 "http://localhost:8080/luceneweb"을 입력하고 이동하면, 이 디렉토리가 생길 것이다.

이동한 디렉토리에 있는 configuration.jsp 파일을 편집한다. 이 파일 안에 보면 indexLocation이라는 String 형 변수가 있다. 이 변수는 인덱스가 생성된 디렉토리의 위치를 저장하게 된다. 이 값이 이전에 지정했던 위치와 동일한지 확인한다.

appTitle과 appFooter String 형 변수도 원하는 값으로 설정할 수 있다. configuration.jsp 설정을 끝마쳤다면 톰캣을 재시작한다.

Running the Demos
브라우저에서 http://localhost:8080/luceneweb 을 입력하고 "test"와 페이지 당 보여질 항목의 개수를 입력한 후 search를 누른다.

이렇게 하면 몇 개의 결과들을 볼 수 있게 될 것이다. 다른 terms들도 검색해 보아라. 설정된 페이지 당 항목의 개수 및 반환된 결과에 따라, 화면 아래 쪽에 "more results>>"라는 링크가 보일 수 있다. 이를 클릭하게 되면 다음 페이지로 이동하게 된다. 만약 인덱스를 열 때 에러가 발생한다면 이는 "configuration.jsp"를 올바르게 설정하지 않았거나, 톰캣에서 접근이 허용되지 않은 디렉토리를 인덱스 디렉토리로 잡았을 가능성이 크다.

다음은 "jsp"라는 단어를 검색한 결과 화면이다.



 

참고 사이트 : http://blog.naver.com/NBlogMain.nhn?blogId=okaydanky&Redirect=Dlog&Qs=%2Fokaydanky%2F5815700&


|


I. Welcom to Lucene !


  Lucene 은 자바로 구현된 고성능의 풀텍스트 검색엔진입니다

  Lucene 이 제공하는 API를 사용하여 강력하고 유연한 검색기능을 어플리케이션에 손쉽게 추가할 수 있습니다

  Lucene은 2005년 2월에 Apache top-level 로 등급이 상승하였고

  서브 프로젝트인 Nutch 또한 2005년 6월에 Apache Incubator를 졸업하였습니다


  Lucene는 다음 3가지 software를 포함하고 있습니다

  Lucene java : Lucene의 핵심 부분으로 indexing 과 search 구현 영역입니다

  Nutch : web search application을 지원합니다 (이슈!)

                 mp3, pdf, ms 등 다양한 문서를 검색할수 있도록 제공해 주지만

                 아직까지는 0.6 버젼이네요

  Lucene4c :  Lucene의 C 기반의 검색엔진입니다 아직까진 Incubator에 있군요


  이번 강좌에서는 Lucene java 함 뒤벼보고 웹에다 Lucene을 달아봅시다 ^^


  강좌 진행 순서는 "데모I 프로그램(어플리 케이션) -> 데모II 프로그램(웹 어플리케이션) -> 데모II 프로그램 수정" 순으로 갑니다


  ps. 한글검색이 가능하지만 한글 형태소 분석을 아직까지는 지원하지 않기 때문에

       한글은 단순검색으로 만족해야 합니다.

       하지만 영문은 기똥차게 잘됩니다



II. Download


  lucene 다운로드

  http://www.apache.org/dyn/closer.cgi/jakarta/lucene/binaries/


  참고 사이트

  http://lucene.apache.org/

  http://lucene.apache.org/java/docs/api/index.html

  http://lucene.apache.org/java/docs/index.html

  http://today.java.net/pub/a/today/2003/11/07/QueryParserRules.html

  http://www-128.ibm.com/developerworks/library/j-lucene/

  http://www.onjava.com/pub/a/onjava/2003/03/05/lucene.html




III. 설치


  그럼 이제 Lucene에 한번 빠져 봅시다~!

  다운받은 lucene-1.4.3.zip 파일을 C:\에 압축을 풉니다




  압축을 풀면 lucene-1.4.3.jarlucene-demos-1.4.3.jar 파일을 클래스 패스에 겁니다



C:\Documents and Settings\Administrator>cd c:\

C:\>cd lu*

C:\lucene-1.4.3>set classpath=C:\lucene-1.4.3\lucene-1.4.3.jar;C:\lucene-1.4.3\lucene-demos-1.4.3.jar


C:\lucene-1.4.3>set
ALLUSERSPROFILE=C:\Documents and Settings\All Users
ANT_HOME=C:\java\Jeus42\lib\etc\ant
APPDATA=C:\Documents and Settings\Administrator\Application Data
CLASSPATH=C:\lucene-1.4.3\lucene-1.4.3.jar;C:\lucene-1.4.3\lucene-demos-1.4.3.jar

...



  "set" 명령으로 확인합니다

  설치 끝 ~



IV. 데모I 실행하기


  Lucene 데모에는 두가지 데모가 있습니다

  하나는 일반적인 인덱싱, 및 검색이고 다른 하나는 웹에서 사용하기 위한 인덱싱 및 웹검색입니다


1) 데모I 실행


먼저 네이버나 야후같은 웹 검색엔진을 생각해 봅시다
수도없이 많은 문서들이 어떻게 해서 그렇게 빠릴 검색될까요?
바로 검색 전처리 작업을 하기 때문입니다
예를들어 간단하게 보자면 "love"라는 단어는 A문서, B문서, C문서에 포함되어 있다라는 정보를 미리 만들어 두는 것입니다
즉 인덱스를 만들어 두는 것이지요
그리고 웹로봇들이 문서를 수집해오면 추가된 문서들에 대해 하루에 몇번씩 배치작업으로 인덱스를 추가해 주겠지요
결과적으로 "love" 검색시 인덱스 정보를 뒤져서 A문서, B문서, C문서의 결과를 보여주는 겁니다


lucene도 마찬가지 입니다 인덱스를 먼저 만들어 주어야 합니다
먼저 일단 데모프로그램을 이용하여 인덱스를 만들어 보고 이를 이용하여 검색해 봅시다
내부 코딩은 일단 실행 이후에 살펴봅시다 ^_^ (눈에 먼저 보여야 멀 해도 잘되죵)


C:\lucene-1.4.3\src\ 는 데모을 위한 자바소스 파일입니다


 

인덱스 생성하기
다음 명령으로 인덱스를 생성해 봅시다
인덱스 생성 어플리케이션은 IndexFiles.java 이며 파라미터는 인덱스를 만들 소스파일들(검색대상파일들) 입니다
여기서는 lucene의 document를 index 처리해 보겠습니다


C:\lucene-1.4.3>
C:\lucene-1.4.3>java org.apache.lucene.demo.IndexFiles C:\lucene-1.4.3\docs
adding C:\lucene-1.4.3\docs\api\allclasses-frame.html
adding C:\lucene-1.4.3\docs\api\allclasses-noframe.html
adding C:\lucene-1.4.3\docs\api\constant-values.html
adding C:\lucene-1.4.3\docs\api\deprecated-list.html
adding C:\lucene-1.4.3\docs\api\help-doc.html
adding C:\lucene-1.4.3\docs\api\index-all.html
adding C:\lucene-1.4.3\docs\api\index.html
adding C:\lucene-1.4.3\docs\api\org\apache\lucene\analysis\Analyzer.html
...
18500 total milliseconds
C:\lucene-1.4.3>


야호~ 인덱스가 생성되었습니다



C:\lucene-1.4.3\index 풀더를보면 다음 파일들이 생성된 것을 알수있습니다


검색하기
검색 어플리케이션은 SearchFiles.java 이며 실행 후 Query: 에 검색할 단어를 입력해 봅시다

C:\lucene-1.4.3>
C:\lucene-1.4.3>java org.apache.lucene.demo.SearchFiles
Query: lucene
Searching for: lucene
324 total matching documents
0. C:\lucene-1.4.3\docs\api\allclasses-frame.html
1. C:\lucene-1.4.3\docs\api\allclasses-noframe.html
2. C:\lucene-1.4.3\docs\api\index-all.html
3. C:\lucene-1.4.3\docs\api\overview-frame.html
4. C:\lucene-1.4.3\docs\api\overview-tree.html
5. C:\lucene-1.4.3\docs\api\org\apache\lucene\queryParser\MultiFieldQueryParser.html
6. C:\lucene-1.4.3\docs\lucene-sandbox\index.html
7. C:\lucene-1.4.3\docs\resources.html
8. C:\lucene-1.4.3\docs\api\org\apache\lucene\search\class-use\Query.html
9. C:\lucene-1.4.3\docs\api\org\apache\lucene\index\class-use\Term.html
more (y/n) ?


와~ 성공! 엄청 빠릅니다!!

검색결과가 10개씩 리스팅되며 다음 리스트는 y버튼을 클릭하여 조회 할수 있습니다



2) 데모I 인덱싱 코드 분석

이 데모 프로그램은 가장 기본이 되는 프로그램으로 핵심 코딩만 되어 있으니 lucene을 사용하기 위해서는 꼭 알아 두어야 합니다


Analyzer 선택

Analyer 는 문서를 인덱싱 하거나 검색할때 핵심이 되는 요소로서, 텍스트를 파싱할 때 사용합니다 Analyzer의 종류에는 다음 몇가지 들이 있습니다


SimpleAnalyzer

  non-letters 를 기준으로 문자를 파싱합니다
  non-letters는 java.lang.Character.isLetter()에 의해 정의된 것을 사용합니다
  이 Analyzer는 대부분의 유럽권 언어에 적당하며 아시아권 언어에는 terrible 이라고 되어 있군요 -_-;
  대소문자 구분 안합니다


StopAnalyzer

  기본적으로 SimpleAnalyzer와 같으나 StopFilter를 두어 StopWord를 제거한 후 분석합니다
  StopWord란 일반적으로 검색시 유용하지 않는 단어들을 말합니다
  (a,an,and,are,as,at,be,but,by,for,if,in,into,is,it,no,not,of,on,or,s,such,t,that,the,their,then,there,these,they,this,to,was,will,with) 역시나 대소문자 구분 안합니다


StandardAnalyzer 

  대부분 유렵권 언어들에 최적화 되어있는 Analyzer 입니다
  StopFilter를 사용하며 대소문자 구분 안합니다


WhitespaceAnalyzer 

  whitespace, 즉 공백문자를 가지고 text를 나누는 방식입니다
  가장 기본적이면서도 무식한 방식입니다
  불행히도 한글검색은 이 WhitespaceAnalyzer 만 가능하며 대소문자 구분 합니다

  (왜 이것만 대소문자 구분 하냥 -_-)


이밖에도 GermanAnalyzer, PerFieldAnalyzerWrapper, RussianAnalyzer등이 있으며
이름에서도 알수있듯이 그다지 한글과 친하지 않은듯 합니다 -.-;;


IndexWriter 생성
자 이제 Analyer를 선택했으면 IndexWriter를 생성하여 Index를 만들어봅시다


IndexWriter writer = new IndexWriter("index", new StandardAnalyzer(), true);


첫번째 파라미터는 index가 생성될 위치를 말하며
두번째 파라미터는 선택한 Analyzer를,
세번째 파라미터는 index를 초기화 하여 다시 생성할것인지 말것인지를 말합니다
즉 추가/삭제만 할 것인지(false) 새로 만들것인지(true)를 나타냅니다
문서가 많을경우 매번 새로 만들수 없으며,
또한 만약 몇개의 문서만 변경되었는데 모두 다시 인덱스를 만들수는 없기 때문입니다 (시간 상당히 걸림 --)


Index에 document 추가
다음으로 소스 디렉토리(검색대상 문서들)의 파일들을 읽어가며 Analyzer에 의해 파싱된 문서 정보를 인덱스에 추가합니다


writer.addDocument(FileDocument.Document(file));


index optimize
마지막으로 인덱싱한 정보를 하나의 파일로 merge 합니다
즉 검색에 적합하도록 파일을 하나로 합치는 겁니다


writer.optimize();


index close

사용후 받드시 close 합시다!


writer.close();


끝~ 간단하죠?

이제 전체 소스를 살펴봅시다

소스는 C:\lucene-1.4.3\src\demo\org\apache\lucene\demo 에 있습니다


org.apache.lucene.demo.IndexFiles.java


class IndexFiles {


  public static void main(String[] args) throws IOException {

    String usage = "java " + IndexFiles.class + " <root_directory>";
   
    // 파라미터(소스디렉토리)를 입력하지 않았다면 사용법을 출력해 줍니다
    if (args.length == 0) {
      System.err.println("Usage: " + usage);
      System.exit(1);
    }

    Date start = new Date();
    try {
   
      // 선택한 Analyzer를 이용하여 IndexWriter를 생성합니다
      IndexWriter writer = new IndexWriter("index", new StandardAnalyzer(), true);
     
      // 소스디렉토리를 디비가며 문서를 파싱하여 인덱스에 추가하는 재귀함수
      indexDocs(writer, new File(args[0]));

      // 인덱싱한 여러 segment들을 검색에 알맞도록 하나로 합치는 작업
      writer.optimize();
     
      // 반드시 close()
      writer.close();

      Date end = new Date();

      // 인덱싱 처리시간 출력
      System.out.print(end.getTime() - start.getTime());
      System.out.println(" total milliseconds");

    } catch (IOException e) {
      System.out.println(" caught a " + e.getClass() +
       "\n with message: " + e.getMessage());
    }
  }


  // 소스 파일들을 읽어가며 파싱하여 인덱스에 추가하는 재귀함수
  public static void indexDocs(IndexWriter writer, File file)
    throws IOException {


    if (file.canRead()) {
      if (file.isDirectory()) {
        String[] files = file.list();


        if (files != null) {
          for (int i = 0; i < files.length; i++) {
            // 자기자신을 호출
            indexDocs(writer, new File(file, files[i]));
          }
        }
      } else {
        System.out.println("adding " + file);
        try {
          // 문서를 인덱스에 추가

          // FileDocument는 해당 file의 정보를 파싱해줌
          writer.addDocument(FileDocument.Document(file));
        }
       
        // 윈도에서 temporary filese등이 access denied로  exception이 발생할 수 있음
        catch (FileNotFoundException fnfe) {
          ;
        }
      }
    }
  }
}



3) 데모I 검색 코드분석
검색은 인덱스를 만드는 코드보다 훨씬 쉽습니다


IndexSearcher 생성
실질적으로 검색을 담당할 IndexSearcher를 생성해 봅시다
파라미터로는 index가 생성되어있는 위치를 입력합니다


Searcher searcher = new IndexSearcher("index");


Query 생성
Query는 질의 문자열을 파싱해 줍니다 (즉 AND,OR,NOT,!,-등의 논리연산이나 와일드카드 *,?등을 파싱합니다)


Query query = QueryParser.parse(line, "contents", analyzer);


첫번째 파라미터는 질의를,
두번째 파라미터는 검색 필드를,
세번째 파라미터는 인덱스를 만든 Analyzer와 동일한 Analyzer를 입력해 줘야 합니다


검색 및 검색한 결과 저장

파싱된 쿼리를 가지고 검색하여 그 결과값을 반환 받습니다


Hits hits = searcher.search(query);


반환된 Hits 클래스는 순위가 매겨진 문서들로 검색결과를 저장하고 유지합니다


IndexSearcher close
검색이 끝났으면 닫아줍시다


searcher.close();


전체 소스를 살펴봅시다


org.apache.lucene.demo.SearchFiles.java

class SearchFiles {


  public static void main(String[] args) {
    try {


      // index 폴더를 파라미터로 넘겨 IndexSearcher를 생성합니다
      Searcher searcher = new IndexSearcher("index");
     
      // 생성된 index와 동일한 Analyzer를 생성하여 넘겨줍니다
      Analyzer analyzer = new StandardAnalyzer();


      // 검색어를 입력받기 위한 reader 입니다
      BufferedReader in = new BufferedReader(new InputStreamReader(System.in));


      while (true) {
        System.out.print("Query: ");
        String line = in.readLine();
       
        if (line.length() == -1)
          break;


        // 입력받은 질의를 파싱합니다
        Query query = QueryParser.parse(line, "contents", analyzer);
        System.out.println("Searching for: " + query.toString("contents"));


        // 팡싱된 질의로 검색을 합니다       
        Hits hits = searcher.search(query);
        System.out.println(hits.length() + " total matching documents");
       
        // 검색 결과 목록을 10개씩 보여줍니다
        final int HITS_PER_PAGE = 10;
        for (int start = 0; start < hits.length(); start += HITS_PER_PAGE) {
          int end = Math.min(hits.length(), start + HITS_PER_PAGE);
          for (int i = start; i < end; i++) {


            // 검색 결과로 부터 문서를 가져옵니다
            Document doc = hits.doc(i);

            // 문서정보를 출력합니다

            String path = doc.get("path");
            if (path != null) {
                  System.out.println(i + ". " + path);
            } else {
                  String url = doc.get("url");
              if (url != null) {
                System.out.println(i + ". " + url);
                System.out.println("   - " + doc.get("title"));
              } else {
                System.out.println(i + ". " + "No path nor URL for this document");
              }
            }
          }


          if (hits.length() > end) {
            System.out.print("more (y/n) ? ");
            line = in.readLine();
            if (line.length() == 0 || line.charAt(0) == 'n')
              break;
          }
        }
      }
     
      searcher.close();
       
    } catch (Exception e) {
      System.out.println(" caught a " + e.getClass() +
         "\n with message: " + e.getMessage());
    }
  }
}



V. 질의 문법

질의 문법에 대해 알아봅시다


A AND B

    A와 B가 모두 포함된 문서를 검색한다

A OR B

    A혹은 B가 포함된 문서를 검색한다

A NOT B

    A는 포함되고 B는 포함되지 않는 문서를 검색한다

    A ! B, A - B와 동일하다

+A OR B

    A OR B에서 A는 받드시 포함된 문서를 검색한다

A*

    A로 시작하는 단어가 있는 문서를 검색한다

A?

    A로 시작하는 두글자의 단어가 있는 문서를 검색한다

A~

    A와 스펠링이 비슷한 글자를 지닌 단어가 있는 문서를 검색한다

(A OR B) AND C

    논리연산의 그루핑 또한 지원한다


AND, OR, NOT등은 반드시 대문자로 입력해야 인식됩니다


다음 시간에는 두번째 데모 프로그램을 실행시켜 보고 lucene을 웹 어플리케이션에 달아 봅시다~


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

본문서는 자유롭게 배포/복사 할수 있지만

이문서의 저자에 대한 언급을 삭제하시면 안됩니다

저자 : GoodBug (unicorn@jakartaproject.com)

최초 : http://www.jakartaproject.com 

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


|

No7Do's Blog is powered by Daum & tistory