'lucene'에 해당되는 글 71건

  1. 2015.11.24 [Lucene] Arirang에 구현된 한글 초성,중성,종성 변환
  2. 2015.11.24 [Lucene] CustomScoreQuery vs. DisjunctionMaxQuery
  3. 2015.11.20 [arirang] 사전 데이터 등록 예제
  4. 2015.11.10 [Elasticsearch] arirang analyzer offset 추출 오류.
  5. 2015.11.04 [Elasticsearch] lucene arirang analyzer 플러그인 적용 on elasticsearch 2.0
  6. 2014.11.05 [Lucene] 4.9.0 analyzer & tokenizer....
  7. 2014.10.17 [ElasticSearch] bitset...
  8. 2014.04.30 [lucene] arirang maven build 하기.
  9. 2014.02.25 [lucene] IndexReader/Fields의 term 추출. 1
  10. 2013.10.11 [Lucene] score 계산식 알아보기.

[Lucene] Arirang에 구현된 한글 초성,중성,종성 변환

ITWeb/검색일반 2015. 11. 24. 17:35

수명님이 이미 다 만들어 놓으셨는데 참 뒷북도 ㅡ.ㅡ;

일단 죄송합니다.


arirang-morph 프로젝트 내 MorphUtil 클래스에 구현되어 있습니다.


[한글 초성/중성/종성 분리]

/**
* 한글 한글자를 초성/중성/종성의 배열로 만들어 반환한다.
* @param c the character to be decomposed
*/
public static char[] decompose(char c) {
char[] result = null;

if(c>0xD7A3||c<0xAC00) return new char[]{c};

c -= 0xAC00;

char choseong = CHOSEONG[c/JUNG_JONG];
c = (char)(c % JUNG_JONG);

char jungseong = JUNGSEONG[c/JONGSEONG.length];

char jongseong = JONGSEONG[c%JONGSEONG.length];

if(jongseong != 0) {
result = new char[] {choseong, jungseong, jongseong};
}else {
result = new char[] {choseong, jungseong};
}
return result;
}



[한글 초성/중성/종성 합침]

public static char compound(int first, int middle, int last) {    
return (char)(0xAC00 + first* JUNG_JONG + middle * JONGSEONG.length + last);
}


:

[Lucene] CustomScoreQuery vs. DisjunctionMaxQuery

ITWeb/검색일반 2015. 11. 24. 15:05

검색 서비스를 운영하다 보면 문서에 대한 부스팅 작업이 필요 할 때가 있습니다.

부스팅의 목적은 다양할 수 있는데요.

한 문장으로 정리를 하면, 

"특정 문서를 검색 결과 상위에 노출시키기 위해 사용"

한다고 보시면 됩니다.


문서에 대한 부스팅 작업은 아래와 같은 방법으로 구현이 가능 합니다.


1. 질의 부스팅

"Query time boosting" 이라는 것은 질의 시 특정 필드 또는 질의어에 대한 가중치를 부여하여 질의 시점에 적용하는 방식을 말합니다.


2. 색인 부스팅

"Index time boosting" 이라는 것은 색인 시 특정 필드 또는 문서에 대한 가중치를 부여하여 색인 시점에 적용하는 방식을 말합니다.


3. 필드 부스팅

"Field boosting" 이라는 것은 특정 필드에 대한 가중치가 또는 중요도가 높다는 것을 반영하여 적용하는 방식을 말합니다.


4. 도큐멘트 부스팅

"Document boosting" 이라는 것은 특정 문서 자체에 대한 가중치가 또는 중요도가 높다는 것을 반영하여 적용하는 방식을 말합니다.


5. 커스텀 부스팅

"Custom boosting" 이라는 것은 임의 문서에 대한 가중치와 스코어에 대한 조작을 통해 적용하는 방식을 말합니다.


부스팅에 대한 구현 방법을 살펴 보았는데요.

이것들은 아래의 API를 통해서 구현 하게 됩니다.


바로 DisjunctionMaxQuery 와 CustomScoreQuery 입니다.

물론 lucene에서 제공하는 다른 API 또는 Elasticsearch 나 Solr 에서 제공하는 다양한 방식으로 구현이 가능 합니다.



DisjunctionMaxQuery 를 이용해서 구현 가능한 것은

1. 질의 부스팅

3. 필드 부스팅

정도로 보입니다.


반대로 CustomScoreQuery 는 다양하게 구현이 가능합니다.

Elasticsearch 기준으로 보면 FunctionScoreQuery + DisjunctionMaxQuery 를 섞어서 사용이 가능 하기 때문에 2. 색인 부스팅을 제외 하고는 다 구현이 가능 하다고 보면 될 것 같습니다.


자 이제 급 마무리를 해보겠습니다.

뭐 말은 만드는 사람 맘이고 해석도 하는 사람 맘이니 저랑 다르게 생각하시는 분들이 계실 겁니다.

다만 내용이 틀렸거나 잘못되었다면 좀 알려주세요. ^^;


[Dis Max Query]

- 질의 시점에 사용을 합니다.

- Field 에 대한 가중치를 주어 부스팅을 합니다.

- 구현하기 쉽습니다.

- 순수하게 검색엔진에 맡겨처 처리 합니다.


[Custom(Function) Score Query]

- 질의 시점에 사용을 합니다.

- Field, Document 에 대한 가중치를 주어 부스팅을 합니다.

- 제공하는 API 가 많기 때문에 어렵지 않습니다.

- 다양한 방법으로 구현이 가능 합니다.

- 다양한 알고리즘 또는 요건을 만족 시키기 위해 사용을 합니다.

- 문서 내 특정 값을 이용하여 부스팅에 적용 할 수 있습니다.

- 복잡할 수록 성능이 느려 질 수 있습니다. 


과거에 fulltext 검색으로 사용하는 게시판류 서비스 뭐 이런데에서는 dis max query + query string 을 즐겨 사용하곤 했는데요.

지금은 좀 더 정교하게 부스팅을 하기 위해서 custom(function) score query 를 많이 사용하는것 같습니다.

특히 쇼핑몰 같은 경우는 dis max 보다는 custom score 가 적합한 query라고 생각 합니다.

:

[arirang] 사전 데이터 등록 예제

ITWeb/검색일반 2015. 11. 20. 15:15

arirang analyzer 를 사용하면서 사전 활용을 위해서는 사전 파일이 어떻게 구성이 되어 있고 관리가 되어야 하는지 알아야 합니다.

아래 공식 카페에 들어가시면 많은 정보들이 있으니 참고 하시면 되겠습니다.


[공식카페]


[형태소분석 사전 구성 및 사용법]


[사전 등록 예시]

# 위 구성 및 사용법 에서와 같이 인덱스 순서가 이렇게 되어 있습니다.

명사 동사 기타품사 하여(다)동사 되어(다)동사 '내'가붙을수있는명사 na na na 불규칙변형


# 엘사는 명사이고 동사, 기타품사, 불규칙이 아니다, 라고 가정하면 아래와 같이 표현이 됩니다.

엘사,100000000X


# 노래는 명사이고 하여 동사가 됩니다.

노래,100100000X


# 소리는 명사이고 소리내다와 같이 내가 붙을 수 있는 명사 입니다.

소리,100001000X


[사전작업 후 리로딩]

arirang-morph 패키지에서 DictionaryUtil.java 내 loadDictionary() 호출을 통해 다시 올려 줍니다.

▶ 별도 구현이 필요합니다.


[불규칙변형 태그]

원문) http://cafe.naver.com/korlucene/135

# 위에서 제일 마지막에 'X' 라는 문자가 있습니다. 이 부분에 대한 설명 입니다.

B : ㅂ 불규칙

H : ㅎ 불규칙

L : 르 불규칙

U : ㄹ 불규칙

S : ㅅ 불규칙

D : ㄷ 불규칙

R : 러 불규칙

X : 규칙


:

[Elasticsearch] arirang analyzer offset 추출 오류.

Elastic/Elasticsearch 2015. 11. 10. 15:38

[아래 문제 회피]

기본적으로 pairmap 관련 기능을 사용하지 않으면 문제를 회피 할 수 있습니다.

더 근본적으로는 관련 기능에 대한 개선이 필요 하겠지만 일단 빠르게 해결 하기 위해서 코드를 제거해 보겠습니다.


대상파일)

KoreanTokenizer.java


삭제 대상코드) 

            if(pairstack.size()>0 && pairstack.get(0)==c) {

                pairstack.remove(0);

                continue;

            }


            int closechar = getPairChar(c);

            if(closechar!=0) {

                if((pairstack.size()==0 || pairstack.get(0)!=closechar) && length>0) {

                    pairstack.add(0,closechar);

                    break;

                } else {

                    pairstack.add(0,closechar);

                    continue;

                }

            }

위 코드를 주석 처리 후 빌드해서 배포 하시면 됩니다.


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


최근에 arirang analyzer plugin을 만들어서 elasticsearch에서 사용하고 있습니다.

사용하다 발견된 버그 공유 합니다.


[색인원본문서]

(‘14.8월)의 일환으로 ’15.3.3 상반기중(행복서울대학교 등 활용)


[Arirang Analyzed]

{

    "tokens": [

        {

            "token": "14",

            "start_offset": 2,

            "end_offset": 4,

            "type": "word",

            "position": 0

        },

        {

            "token": "8월",

            "start_offset": 5,

            "end_offset": 7,

            "type": "korean",

            "position": 1

        },

        {

            "token": "의",

            "start_offset": 8,

            "end_offset": 9,

            "type": "korean",

            "position": 2

        },

        {

            "token": "일환",

            "start_offset": 10,

            "end_offset": 12,

            "type": "korean",

            "position": 3

        },

        {

            "token": "15",

            "start_offset": 16,

            "end_offset": 18,

            "type": "word",

            "position": 4

        },

        {

            "token": "3",

            "start_offset": 19,

            "end_offset": 20,

            "type": "word",

            "position": 5

        },

        {

            "token": "3",

            "start_offset": 21,

            "end_offset": 22,

            "type": "word",

            "position": 6

        },

        {

            "token": "상반기중행복서울대학교",

            "start_offset": 23,

            "end_offset": 34,

            "type": "korean",

            "position": 7

        },

        {

            "token": "상반",

            "start_offset": 23,

            "end_offset": 25,

            "type": "korean",

            "position": 7

        },

        {

            "token": "기중",

            "start_offset": 25,

            "end_offset": 27,

            "type": "korean",

            "position": 8

        },

        {

            "token": "행복",

            "start_offset": 27,

            "end_offset": 29,

            "type": "korean",

            "position": 9

        },

        {

            "token": "서울",

            "start_offset": 29,

            "end_offset": 31,

            "type": "korean",

            "position": 10

        },

        {

            "token": "대학교",

            "start_offset": 31,

            "end_offset": 34,

            "type": "korean",

            "position": 11

        },

        {

            "token": "등",

            "start_offset": 36,

            "end_offset": 37,

            "type": "korean",

            "position": 12

        },

        {

            "token": "활용",

            "start_offset": 38,

            "end_offset": 40,

            "type": "korean",

            "position": 13

        }

    ]

}


여기서 보시면 "행복"에서 부터 offset 정보가 하나씩 줄어든것을 확인 할 수 있습니다.


[원본 변경을 통한 문제해결 - 하나]

(‘14.8월)의 일환으로 15.3.3 상반기중(행복서울대학교 등 활용)

- ’15 (apostrophe) 제거


[원본 변경을 통한 문제해결 - 둘]

(‘14.8월)의 일환으로 ’15.3.3 상반기중(행복서울대학교 등 활용)

- 8월’ (apostrophe) 추가


[원본 변경을 통한 문제해결 - 셋]

(14.8월)의 일환으로 ’15.3.3 상반기중(행복서울대학교 등 활용)

- ’14 (apostrophe) 제거


[원본 변경을 통한 문제해결 - 넷]

‘14.8월)의 일환으로 ’15.3.3 상반기중(행복서울대학교 등 활용)

- ( 제거


[해결 방법?]

- 복합 pairmap 구성에 대한 arirang analyzer 오류 수정 (tokenizer 와 filter 쪽 수정이 필요해 보입니다.)

- 원본에 대한 character normalization 작업을 통해 filter 를 합니다.

:

[Elasticsearch] lucene arirang analyzer 플러그인 적용 on elasticsearch 2.0

Elastic/Elasticsearch 2015. 11. 4. 15:37

elasticsearch 2.0 GA 기념으로 수명님의 lucene arirang 한글분석기 적용방법을 알아 보도록 하겠습니다.

이전에 작성된 elasticsearch analyzer arirang 은 아래 글 참고 부탁 드립니다.


http://jjeong.tistory.com/958


[Requirement]

elasticsearch 2.0

jdk 1.7 이상 (elastic 에서 추천 하는 버전은 1.8 이상입니다.)

maven 3.1 이상

arirang.lucene-analyzer-5.0-1.0.0.jar (http://cafe.naver.com/korlucene/1274)

arirang-morph-1.0.0.jar (http://cafe.naver.com/korlucene/1274)


[Analysis Plugins]

https://www.elastic.co/guide/en/elasticsearch/plugins/2.0/analysis.html


[Plugin 작성 시 변경 내용 - 하나]

- es-plugin.properties 파일이 없어 지고 plugin-descriptor.properties 가 생겼습니다.

- plugin-descriptor.properties 내용은 아래와 같습니다.


classname=org.elasticsearch.plugin.analysis.arirang.AnalysisArirangPlugin

name=arirang

jvm=true

java.version=1.7

site=false

isolated=true

description=Arirang plugin

version=${project.version}

elasticsearch.version=${elasticsearch.version}

hash=${buildNumber}

timestamp=${timestamp}


▶ 자세한 설명을 원하시는 분들은 아래 링크 참고 하시면 됩니다.

https://www.elastic.co/guide/en/elasticsearch/plugins/current/plugin-authors.html#_plugin_descriptor_file


[Plugin 작성 시 변경 내용 - 둘]

- 기존에 상속 받았던 AbstractPlugin이 없어지고 Plugin을 상속 받아 구현하도록 변경 되었습니다.

From.

public class AnalysisArirangPlugin extends AbstractPlugin {...}


To.

public class AnalysisArirangPlugin extends Plugin {...}


그 밖에는 변경된 내용은 아래 arirang 에서 바뀐 부분이 적용된 내용이 전부 입니다.


[Arirang 변경 내용]

- KoreanAnalyzer 에서 lucene version 정보를 받았으나 이제는 정보를 받지 않습니다.

From.

analyzer = new KoreanAnalyzer(Lucene.VERSION.LUCENE_47);


To.

analyzer = new KoreanAnalyzer();


- KoreanTokenizer 에서는 기존에 reader 정보를 받았으나 이제는 정보를 받지 않습니다.

From.

return new KoreanTokenizer(reader);


To.

return new KoreanTokenizer();


[2.0 적용 시 바뀐 내용]

- assemblies/plugin.xml을 수정 하였습니다.

plugins 폴더에 zip 파일 올려 두고 압축 풀면 바로 동작 할 수 있도록 구성을 변경 하였습니다.


<?xml version="1.0"?>

<assembly>

  <id>plugin</id>

  <formats>

      <format>zip</format>

  </formats>

  <includeBaseDirectory>false</includeBaseDirectory>


  <files>

    <file>

      <source>lib/arirang.lucene-analyzer-5.0-1.0.0.jar</source>

      <outputDirectory>analysis-arirang</outputDirectory>

    </file>

    <file>

      <source>lib/arirang-morph-1.0.0.jar</source>

      <outputDirectory>analysis-arirang</outputDirectory>

    </file>

    <file>

      <source>target/elasticsearch-analysis-arirang-1.0.0.jar</source>

      <outputDirectory>analysis-arirang</outputDirectory>

    </file>

    <file>

      <source>${basedir}/src/main/resources/plugin-descriptor.properties</source>

      <outputDirectory>analysis-arirang</outputDirectory>

      <filtered>true</filtered>

    </file>

  </files>

</assembly>

코드는 직관적이라서 쉽게 이해 하실 수 있을 거라 생각 합니다.

필요한 jar 파일들과 properties 파일을 analysis-arirang 이라는 폴더로 묶는 것입니다.

<filtered>true</filtered> 옵션은 아래 링크 참고 하세요. (해당 파일이 filtering 되었는지 확인 하는 것입니다.)

https://maven.apache.org/plugins/maven-assembly-plugin/assembly.html#class_file


여기서 plugin-descriptor.properties 파일이 포함이 안되어 있게 되면 elasticsearch 실행 시 에러가 발생하고 실행이 안됩니다.

주의 하셔야 하는 부분(?) 입니다.


- plugin-descriptor.properties 파일 없을 때 에러 메시지


[2015-11-04 12:34:14,522][INFO ][node                     ] [Lady Jacqueline Falsworth Crichton] initializing ...


Exception in thread "main" java.lang.IllegalStateException: Unable to initialize plugins

Likely root cause: java.nio.file.NoSuchFileException: /Users/hwjeong/server/app/elasticsearch/elasticsearch-2.0.0/plugins/analysis-arirang/plugin-descriptor.properties

at sun.nio.fs.UnixException.translateToIOException(UnixException.java:86)

at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:102)

at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:107)

at sun.nio.fs.UnixFileSystemProvider.newByteChannel(UnixFileSystemProvider.java:214)

at java.nio.file.Files.newByteChannel(Files.java:315)

at java.nio.file.Files.newByteChannel(Files.java:361)

at java.nio.file.spi.FileSystemProvider.newInputStream(FileSystemProvider.java:380)

at java.nio.file.Files.newInputStream(Files.java:106)

at org.elasticsearch.plugins.PluginInfo.readFromProperties(PluginInfo.java:86)

at org.elasticsearch.plugins.PluginsService.getPluginBundles(PluginsService.java:306)

at org.elasticsearch.plugins.PluginsService.<init>(PluginsService.java:112)

at org.elasticsearch.node.Node.<init>(Node.java:144)

at org.elasticsearch.node.NodeBuilder.build(NodeBuilder.java:145)

at org.elasticsearch.bootstrap.Bootstrap.setup(Bootstrap.java:170)

at org.elasticsearch.bootstrap.Bootstrap.init(Bootstrap.java:270)

at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:35)

Refer to the log for complete error details.


- Test Code 추가

뭐가 coverage 를 올리기 위한 그런 테스트 코드는 아닙니다. ;;


▶ ArirangAnalysisTest.java


이 테스트는 elasticsearch에서 실제 작성된 플러그인이 제대로 module 로 등록 되고 등록된 module에 대한 service 를 가져 오는지 보는 것입니다.

elasticsearch 소스코드를 내려 받으시면 plugins 에 들어 있는 코드 그대로 copy & paste 한 것입니다.


▶ ArirangAnalyzerTest.java


이 테스트는 _analyze 에 대한 REST API 와 실제 index.analysis 세팅 사이에 구성이 어떻게 코드로 반영 되는지 상호 맵핑 하기 위해 작성 되었습니다.

analyzer, tokenizer, tokenfilter 에 대해서 어떻게 동작 하는지 그나마 쉽게 이해 하시는데 도움이 될까 싶어 작성된 코드 입니다.


※ Elasticsearch Test Suite 이슈 - 자답(?)

현재 master branch 는 문제 없이 잘 됩니다.

다만 2.0 branch 에서는 아래와 같은 또는 다른 문제가 발생을 합니다.

그냥 master 받아서 테스트 하시길 권장 합니다.


※ Elasticsearch Test Suite 이슈.

이건 제가 잘못해서 발생 한 것일 수도 있기 때문에 혹시 해결 하신 분이 계시면 공유 좀 부탁 드립니다.


▶ 발생 에러

/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/bin/java -ea -Didea.launcher.port=7533 "-Didea.launcher.bin.path=/Applications/IntelliJ IDEA 14 CE.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath "/Applications/IntelliJ IDEA 14 CE.app/Contents/lib/idea_rt.jar:/Applications/IntelliJ IDEA 14 CE.app/Contents/plugins/junit/lib/junit-rt.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/lib/javafx-doclet.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/lib/tools.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre/lib/htmlconverter.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre/lib/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre/lib/rt.jar:/Users/hwjeong/git/elasticsearch-analysis-arirang/target/test-classes:/Users/hwjeong/git/elasticsearch-analysis-arirang/target/classes:/Users/hwjeong/.m2/repository/org/apache/lucene/lucene-core/5.2.1/lucene-core-5.2.1.jar:/Users/hwjeong/.m2/repository/org/elasticsearch/elasticsearch/2.0.0/elasticsearch-2.0.0.jar:/Users/hwjeong/.m2/repository/org/apache/lucene/lucene-backward-codecs/5.2.1/lucene-backward-codecs-5.2.1.jar:/Users/hwjeong/.m2/repository/org/apache/lucene/lucene-analyzers-common/5.2.1/lucene-analyzers-common-5.2.1.jar:/Users/hwjeong/.m2/repository/org/apache/lucene/lucene-queries/5.2.1/lucene-queries-5.2.1.jar:/Users/hwjeong/.m2/repository/org/apache/lucene/lucene-memory/5.2.1/lucene-memory-5.2.1.jar:/Users/hwjeong/.m2/repository/org/apache/lucene/lucene-highlighter/5.2.1/lucene-highlighter-5.2.1.jar:/Users/hwjeong/.m2/repository/org/apache/lucene/lucene-queryparser/5.2.1/lucene-queryparser-5.2.1.jar:/Users/hwjeong/.m2/repository/org/apache/lucene/lucene-sandbox/5.2.1/lucene-sandbox-5.2.1.jar:/Users/hwjeong/.m2/repository/org/apache/lucene/lucene-suggest/5.2.1/lucene-suggest-5.2.1.jar:/Users/hwjeong/.m2/repository/org/apache/lucene/lucene-misc/5.2.1/lucene-misc-5.2.1.jar:/Users/hwjeong/.m2/repository/org/apache/lucene/lucene-join/5.2.1/lucene-join-5.2.1.jar:/Users/hwjeong/.m2/repository/org/apache/lucene/lucene-grouping/5.2.1/lucene-grouping-5.2.1.jar:/Users/hwjeong/.m2/repository/org/apache/lucene/lucene-spatial/5.2.1/lucene-spatial-5.2.1.jar:/Users/hwjeong/.m2/repository/com/spatial4j/spatial4j/0.4.1/spatial4j-0.4.1.jar:/Users/hwjeong/.m2/repository/com/google/guava/guava/18.0/guava-18.0.jar:/Users/hwjeong/.m2/repository/com/carrotsearch/hppc/0.7.1/hppc-0.7.1.jar:/Users/hwjeong/.m2/repository/joda-time/joda-time/2.8.2/joda-time-2.8.2.jar:/Users/hwjeong/.m2/repository/org/joda/joda-convert/1.2/joda-convert-1.2.jar:/Users/hwjeong/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.5.3/jackson-core-2.5.3.jar:/Users/hwjeong/.m2/repository/com/fasterxml/jackson/dataformat/jackson-dataformat-smile/2.5.3/jackson-dataformat-smile-2.5.3.jar:/Users/hwjeong/.m2/repository/com/fasterxml/jackson/dataformat/jackson-dataformat-yaml/2.5.3/jackson-dataformat-yaml-2.5.3.jar:/Users/hwjeong/.m2/repository/org/yaml/snakeyaml/1.12/snakeyaml-1.12.jar:/Users/hwjeong/.m2/repository/com/fasterxml/jackson/dataformat/jackson-dataformat-cbor/2.5.3/jackson-dataformat-cbor-2.5.3.jar:/Users/hwjeong/.m2/repository/io/netty/netty/3.10.5.Final/netty-3.10.5.Final.jar:/Users/hwjeong/.m2/repository/com/ning/compress-lzf/1.0.2/compress-lzf-1.0.2.jar:/Users/hwjeong/.m2/repository/com/tdunning/t-digest/3.0/t-digest-3.0.jar:/Users/hwjeong/.m2/repository/org/hdrhistogram/HdrHistogram/2.1.6/HdrHistogram-2.1.6.jar:/Users/hwjeong/.m2/repository/commons-cli/commons-cli/1.3.1/commons-cli-1.3.1.jar:/Users/hwjeong/.m2/repository/com/twitter/jsr166e/1.1.0/jsr166e-1.1.0.jar:/Users/hwjeong/.m2/repository/log4j/log4j/1.2.16/log4j-1.2.16.jar:/Users/hwjeong/.m2/repository/org/slf4j/slf4j-api/1.6.2/slf4j-api-1.6.2.jar:/Users/hwjeong/.m2/repository/org/slf4j/slf4j-log4j12/1.6.2/slf4j-log4j12-1.6.2.jar:/Users/hwjeong/git/elasticsearch-analysis-arirang/lib/arirang-morph-1.0.0.jar:/Users/hwjeong/git/elasticsearch-analysis-arirang/lib/arirang.lucene-analyzer-5.0-1.0.0.jar:/Users/hwjeong/.m2/repository/junit/junit/4.11/junit-4.11.jar:/Users/hwjeong/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar:/Users/hwjeong/.m2/repository/com/carrotsearch/randomizedtesting/randomizedtesting-runner/2.1.16/randomizedtesting-runner-2.1.16.jar:/Users/hwjeong/.m2/repository/org/hamcrest/hamcrest-all/1.3/hamcrest-all-1.3.jar:/Users/hwjeong/.m2/repository/org/apache/lucene/lucene-test-framework/5.2.1/lucene-test-framework-5.2.1.jar:/Users/hwjeong/.m2/repository/org/apache/lucene/lucene-codecs/5.2.1/lucene-codecs-5.2.1.jar:/Users/hwjeong/.m2/repository/org/apache/ant/ant/1.8.2/ant-1.8.2.jar:/Users/hwjeong/.m2/repository/org/elasticsearch/elasticsearch/2.0.0/elasticsearch-2.0.0-tests.jar:/Users/hwjeong/.m2/repository/net/java/dev/jna/jna/4.1.0/jna-4.1.0.jar" com.intellij.rt.execution.application.AppMain com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 org.elasticsearch.index.analysis.ArirangAnalysisTest,testArirangAnalysis

log4j:WARN No appenders could be found for logger (org.elasticsearch.bootstrap).

log4j:WARN Please initialize the log4j system properly.

log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.


java.lang.RuntimeException: found jar hell in test classpath

at org.elasticsearch.bootstrap.BootstrapForTesting.<clinit>(BootstrapForTesting.java:63)

at org.elasticsearch.test.ESTestCase.<clinit>(ESTestCase.java:106)

at java.lang.Class.forName0(Native Method)

at java.lang.Class.forName(Class.java:270)

at com.carrotsearch.randomizedtesting.RandomizedRunner$1.run(RandomizedRunner.java:573)

Caused by: java.lang.IllegalStateException: jar hell!

class: org.hamcrest.BaseDescription

jar1: /Users/hwjeong/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar

jar2: /Users/hwjeong/.m2/repository/org/hamcrest/hamcrest-all/1.3/hamcrest-all-1.3.jar

at org.elasticsearch.bootstrap.JarHell.checkClass(JarHell.java:267)

at org.elasticsearch.bootstrap.JarHell.checkJarHell(JarHell.java:185)

at org.elasticsearch.bootstrap.JarHell.checkJarHell(JarHell.java:86)

at org.elasticsearch.bootstrap.BootstrapForTesting.<clinit>(BootstrapForTesting.java:61)

... 4 more


:

[Lucene] 4.9.0 analyzer & tokenizer....

Elastic/Elasticsearch 2014. 11. 5. 13:05

http://lucene.apache.org/core/4_9_0/core/org/apache/lucene/analysis/package-summary.html

https://lucene.apache.org/core/4_9_0/core/org/apache/lucene/analysis/TokenStream.html

Version matchVersion = Version.LUCENE_XY; // Substitute desired Lucene version for XY Analyzer analyzer = new StandardAnalyzer(matchVersion); // or any other analyzer TokenStream ts = analyzer.tokenStream("myfield", new StringReader("some text goes here")); OffsetAttribute offsetAtt = ts.addAttribute(OffsetAttribute.class); try { ts.reset(); // Resets this stream to the beginning. (Required) while (ts.incrementToken()) { // Use AttributeSource.reflectAsString(boolean) // for token stream debugging. System.out.println("token: " + ts.reflectAsString(true)); System.out.println("token start offset: " + offsetAtt.startOffset()); System.out.println(" token end offset: " + offsetAtt.endOffset()); } ts.end(); // Perform end-of-stream operations, e.g. set the final offset. } finally { ts.close(); // Release resources associated with this stream. }


The workflow of the new TokenStream API is as follows:

  1. Instantiation of TokenStream/TokenFilters which add/get attributes to/from the AttributeSource.
  2. The consumer calls reset().
  3. The consumer retrieves attributes from the stream and stores local references to all attributes it wants to access.
  4. The consumer calls incrementToken() until it returns false consuming the attributes after each call.
  5. The consumer calls end() so that any end-of-stream operations can be performed.
  6. The consumer calls close() to release any resource when finished using the TokenStream.



이전 버전이랑 바뀐 내용이 있으니 확인하셔야 합니다. :)

:

[ElasticSearch] bitset...

Elastic/Elasticsearch 2014. 10. 17. 18:25

내 블로그에 안남기고 페북에만 남겼내..ㅋㅋ


그냥 지나가다가...

질의 성능 최적화에서 queries vs filters 에 대해 이해하고 사용하고 계실줄로 압니다만, ^^;

요기에 추가로 bitset 에 대해서도 내용이 나오기 때문에 그냥 참고하시라고 링크 던져 봅니다. ^^

filter 가 빠르다라고 이야기 하는 부분에서 bitset에 대한 이해가 없으면 안될것 같아서요.

https://lucene.apache.org/core/4_10_1/core/org/apache/lucene/util/OpenBitSet.html

쉽게는 term filter 했을 떄 match 된 term 에 대해서 bitset 을 1로 marking 해 두어 다음에 이 bitset 만 보고 문서를 리턴하게 된다 뭐 그런 이야기 입니다.


:

[lucene] arirang maven build 하기.

Elastic/Elasticsearch 2014. 4. 30. 15:26

elasticsearch 에 한글형태소 분석기로 arirang 을 적용해 보려고 합니다.

그 전에 먼저 arirang 을 받아서 빌드 테스트를 해보고 lucene 4.7.2 로 빌드가 잘 되면 elasticsearch 1.1.1 용 플러그인으로 만들것입니다.


자세한 내용은 카페에서 확인하세요.

http://cafe.naver.com/korlucene


- SVN

https://lucenekorean.svn.sourceforge.net/svnroot/lucenekorean


- Build 조건

Maven 3.x

JDK 1.7


저는 그냥 

https://lucenekorean.svn.sourceforge.net/svnroot/lucenekorean/arirang.lucene-analyzer-4.6

받아서 4.7.2 로 수정해서 빌드 했습니다.


@수명님이 주의 사항을 카페에 올려 두신게 있는데요 arirang.morph 먼저 빌드 하신 후 analyzer 를 빌드 하셔야 합니다.

이건 pom.xml 열어 보시면 아실듯.. 


일단 4.7.2 로 빌드 잘 되내요.

플러그인 적용 방법은 따로 공유 드리겠습니다.

다 아시는 분들에게는 별로 도움도 안되겠내요.. ^^;;

:

[lucene] IndexReader/Fields의 term 추출.

Elastic/Elasticsearch 2014. 2. 25. 11:19

Reference :

http://lucene.apache.org/core/4_4_0/core/org/apache/lucene/index/IndexReader.html

https://lucene.apache.org/core/4_4_0/core/org/apache/lucene/index/Fields.html


어느분이 물어 보셔서 공유 합니다.
현재 색인된 파일에서 색인된 term을 추출하고 싶으신 분들이 계신것 같습니다.

용도와 목적은 잘 모르겠지만 뭐 필요 하시니까 찾으시겠죠.


하지만 groupby 같은 기능을 구현하려고 하시는 거라면 그냥 facet을 사용하라고 추천 하고 싶습니다.


위에 링크 걸어 놓은 것 처럼 루씬의 IndexReader 를 이용해서 구현 가능 합니다.

IndexReader.getTermVectors(docID) : 문서 전체 term list

IndexReader.getTermVector(docId, field) : 문서의 특정 field 내 term list

문서에 설명이 잘 나와 있으니 참고하세요.

그리고 elasticsearch 에서는  ShardTermVectorService 에서 관련 기능을 제공하고 있습니다.


아래는 IndexReader 소스코드 입니다.


아래는 Fields 소스코드 입니다.



:

[Lucene] score 계산식 알아보기.

Elastic/Elasticsearch 2013. 10. 11. 11:25
필요해서 어제 공부 좀 했습니다.

제가 elasticsearch 로 프로젝트를 진행 하고 있습니다.

랭킹과 문서 스코어링 관련해서 문의가 있어서 정확하게 설명을 해줘야 튜닝에 도움이 될 것 같아 글 좀 남겨 봅니다.


검색해 보시면 많은 문서들이 나오는데요.

아래 문서 참고 하시면 좋을 것 같내요.


[참고링크]

http://www.lucenetutorial.com/advanced-topics/scoring.html

http://devyongsik.tistory.com/364 (여긴 울 회사 재화님도 알고 계신 DEV용식님 사이트인데요. 작성 된지 좀 되었지만 이해 하기에는 좋습니다.)

https://lucene.apache.org/core/3_6_2/scoring.html

http://lucene.apache.org/core/4_5_0/core/org/apache/lucene/search/package-summary.html#package_description

http://lucene.apache.org/core/4_5_0/core/org/apache/lucene/search/similarities/TFIDFSimilarity.html  


[참고용 소스코드]

Similarity.java

DefaultSimilarity.java

TFIDFSimilarity.java


lucene 이나 elasticsearch 나 기본은 바로 위에 있는 넘들 가지고 similarity 계산을 하게 됩니다.

소스를 보시면 아시겠지만 아래 요소를 가지고 score 를 계산 합니다.


tf

idf

lengthNorm

queryNorm

coord


소스코드에서 식을 뽑아 보면 이렇습니다.


 TF

 (float)Math.sqrt(freq)

 IDF

 (float)(Math.log(numDocs/(double)(docFreq+1)) + 1.0)^2

 lengthNorm

 state.getBoost() * ((float) (1.0 / Math.sqrt(numTerms)))

 queryNorm

 (float)(1.0 / Math.sqrt(sumOfSquaredWeights))

 coord

 overlap / (float)maxOverlap


이런건 그냥 위에 나온거 보면 다 나오구요.

검색 질의 시 스코어 계산 유형을 살펴 보겠습니다.

(계산 할 때 위에 식에 넣어서 계산 하기 번거로우니 explain 떠서 나온 값들을 사용해서 계산 하도록 하세요.)


1. 검색어 하나 질의

쉽게는 explain 에서 나온 queryWeight * fieldWeight 를 곱하시면 score 가 나옵니다.

score = (queryWeight * fieldWeight)^2


TFIDFSimilarity.html 에 잘 나와 있죠.

score(q,d)   =   coord(q,d)  ·  queryNorm(q)  · ( tf(t in d)  ·  idf(t)2  ·  t.getBoost() ·  norm(t,d) )
t in q
Lucene Practical Scoring Function

이걸 엑셀 같은 데 식을 넣어서 계산 해 보면 값이 나오게 됩니다.

아래 2번에서 풀어 놓은 식을 참고하세요.


2. 검색어 여러개 질의

score = (queryNorm * SUM( tf * idf^2 * fieldBoost * fieldNorm) )^2


3. 필드 부스팅을 포함한 검색어 질의

쉽게는 아래 처럼 풀어서 이해 하시면 됩니다.

score = ((queryWeight * fieldWeight) + (queryWeight * fieldWeight))^2

-> 필드 부스팅 된 필드의 queryWeight 값은 기본 계산이 되어서 나오지만 같은 필드에 같은 term 으로 했을 경우 기본 queryWeight 에 곱하기 boostScore 만큼 해준다고 보면 됩니다.


여기서 필드 부스팅을 한개가 아닌 여러개를 했다면 (queryWeight * fieldWeight) 이넘을 여러번 계산 해서 더하시면 됩니다.


근데 여기서 궁금한거 하나.... 

- fieldNorm 과 sumOfSquaredWeights 는 어떻게 구하나요???

소스 코드를 보시면 됩니다.


[fieldNorm]

computeNorm(), encodeNormValue(), decodeNormValue(), NORM_TABLE 을 참고하세요.

풀면 결국 아래와 같이 됩니다.


fieldNorm = NORM_TABLE[(floatToByte315(1/SQRT(fieldTotalTermsNum)) & 0xFF)];


[sumOfSquaredWeights]

말 처럼 이건 각각의 term 에 대해서 더하셔야 합니다.

1번에서 처럼  sigma 가 붙어 있는 걸 잊으시면 안됩니다.

이해를 돕고자 풀면 아래와 같이 됩니다.

queryBoost^2 * SUM( (idf * fieldBoost)^2 )


가볍게 이해 하는 수준으로만 사용하시고 깊이 있게 이해를 하고 싶으신 분들은 소스 코드를 꼭 드려야 보세요. :)


:
◀ PREV : [1] : [2] : [3] : [4] : [5] : [6] : [7] : [8] : NEXT ▶