Lucene은 증분 색인 ( incremental indexing)을 지원한다.
incremental indexing을 하기 위해서는 기존의 인덱스와 새로 추가하는 문서들의
인덱스를 합치는 작업을 해야하는데 이때 MergePolicy 클래스에서 이러한
작업들의 기본 설정을 관리하게 되며 3.0.1 버전을 기준으로 봤을때
대략 다음과 같이 3개의 Policy 클래스가 있다.
1. LogByteSizeMergePolicy
2. LogDocMergePolicy
3. LogMergePolicy
Lucene에서는 LogByteSizeMergePolicy를 기본설정으로 사용하고 있다.
$LUENE_HOME/src/java/org/apache/lucene/index 폴더에서 이러한 Policy 클래스
가 들어있고 IndexWriter.java의 소스를 보면 이러한 정책들이 셋팅되어 있는
것을 확인할수 있다.
LogByteMergePolicy의 알고리즘은
http://nlp.stanford.edu/IR-book/html/htmledition/dynamic-indexing-1.html에 잘 나와있다.
http://blog.mikemccandless.com/2011/02/visualizing-lucenes-segment-merges.html
위의 블로그에 가보면 블로그 저자가 TieredMergePolicy라는 새로운 policy를
만들고 LUCENE-854 patch로 만들었다고 하는데 lucene-3.3.0 버전에는
TieredMergePolicy가 포함되어 있다.
2011년 7월 17일 일요일
bloom filter
석사 졸업 논문으로 위키피디아를 이용하여 검색 정확도를 향상시키는
주제에 관하여 논문을 작성하였다.
논문 실험에서 TREC WT10G 데이터(약 4G)를 인덱싱하는데 대략 3시간
쯤 걸린듯하다. 내가 제안하는 알고리즘은 위키피디아의 Entry를 이용하여
랭킹 알고리즘을 수정하였기 때문에 각 다큐먼트를 인덱싱할때에 다큐먼트의
모든 TERM에 대해서 위키피디아의 엔트리로 존재하는지를 검색해야하고
이때문에 초기에는 위키피디아 entry를 DB에 모두 저장하여 실험을 하여보았다.
DB를 이용했을때 대략 WT10G 데이터 전체를 인덱싱하는데에
10시간쯤 걸린듯 하다.
이에 성능을 높이기 위해 bloom filter를 고려하게 되었다.
Bloom filter는 특정 data가 존재하는지의 여부만을 알고자 할때 매우 효율적이고
논문의 랭킹 알고리즘에서는 해당하는 TERM이 위키피디아 entry로 존재하는지
의 여부만을 알면 되기 떄문에 굳이 DB를 사용할 필요가 없고 Bloom filter도
이러한 목적으로는 충분하다.
위키피디아 entry 전체( 약 700만개의 word)를 bloom filter에 저장하게 되면
설정에 따라 다르겠지만 대략 500M정도의 메모리를 사용하게 된다.
대신에 메모리에 직접 올라가기 떄문에 DB를 이용하는 것 보다 훨씬 빨라져서
인덱싱하는데 대략 3시간 30분 정도 걸린듯 하다. 즉 추가적인 entry 검색으로
30분 정도가 걸린것으로 볼수 있다. DB검색에 7시간 정도 걸린것에 비해보면
매우 효율적이라 볼수 있다.
내가 사용한 bloom filter의 소스를 링크한다.
https://sites.google.com/site/wittgena/upload_file/BloomFilter.java?attredirects=0&d=1
주제에 관하여 논문을 작성하였다.
논문 실험에서 TREC WT10G 데이터(약 4G)를 인덱싱하는데 대략 3시간
쯤 걸린듯하다. 내가 제안하는 알고리즘은 위키피디아의 Entry를 이용하여
랭킹 알고리즘을 수정하였기 때문에 각 다큐먼트를 인덱싱할때에 다큐먼트의
모든 TERM에 대해서 위키피디아의 엔트리로 존재하는지를 검색해야하고
이때문에 초기에는 위키피디아 entry를 DB에 모두 저장하여 실험을 하여보았다.
DB를 이용했을때 대략 WT10G 데이터 전체를 인덱싱하는데에
10시간쯤 걸린듯 하다.
이에 성능을 높이기 위해 bloom filter를 고려하게 되었다.
Bloom filter는 특정 data가 존재하는지의 여부만을 알고자 할때 매우 효율적이고
논문의 랭킹 알고리즘에서는 해당하는 TERM이 위키피디아 entry로 존재하는지
의 여부만을 알면 되기 떄문에 굳이 DB를 사용할 필요가 없고 Bloom filter도
이러한 목적으로는 충분하다.
위키피디아 entry 전체( 약 700만개의 word)를 bloom filter에 저장하게 되면
설정에 따라 다르겠지만 대략 500M정도의 메모리를 사용하게 된다.
대신에 메모리에 직접 올라가기 떄문에 DB를 이용하는 것 보다 훨씬 빨라져서
인덱싱하는데 대략 3시간 30분 정도 걸린듯 하다. 즉 추가적인 entry 검색으로
30분 정도가 걸린것으로 볼수 있다. DB검색에 7시간 정도 걸린것에 비해보면
매우 효율적이라 볼수 있다.
내가 사용한 bloom filter의 소스를 링크한다.
https://sites.google.com/site/wittgena/upload_file/BloomFilter.java?attredirects=0&d=1
2011년 7월 16일 토요일
linux kernel의 cache clean과 cache flush
ARM System Developer's Guide에 보면
cache clean과 cache flush에 대해서 자세히 설명되어 있다.
flush는 cache를 그냥 비워버리고 clean은 write buffer의 데이터를
메모리에 write한 후 cache를 지운다.
커널의 코드를 살펴보면 다음과 같다. ( 2.6.13 버젼 기준 )
static inline void flush_pmd_entry(pmd_t *pmd)
{
const unsigned int __tlb_flag = __cpu_tlb_flags;
if (tlb_flag(TLB_DCLEAN))
asm("mcr p15, 0, %0, c7, c10, 1 @ flush_pmd"
: : "r" (pmd) : "cc");
if (tlb_flag(TLB_WB))
dsb();
}
static inline void clean_pmd_entry(pmd_t *pmd)
{
const unsigned int __tlb_flag = __cpu_tlb_flags;
if (tlb_flag(TLB_DCLEAN))
asm("mcr p15, 0, %0, c7, c10, 1 @ flush_pmd"
: : "r" (pmd) : "cc");
}
flush 의 경우에는
if (tlb_flag(TLB_WB)) dsb();
코드가 있어서 write back 캐시정책을 사용하는 경우에는
장벽을 사용해서 write buffer까지 비워버린다.
따라서 flush의 경우에는 캐시에서 지우게 되는 라인이 메모리에 쓰여지지 않고
clean의 경우에는 지우는 라인의 데이터가 write buffer에 남아있으므로
메모리에 쓰여지게 되는 결과가 나타나게 된다.
정리하면 다음과 같다.
Clear
cache clean과 cache flush에 대해서 자세히 설명되어 있다.
flush는 cache를 그냥 비워버리고 clean은 write buffer의 데이터를
메모리에 write한 후 cache를 지운다.
커널의 코드를 살펴보면 다음과 같다. ( 2.6.13 버젼 기준 )
static inline void flush_pmd_entry(pmd_t *pmd)
{
const unsigned int __tlb_flag = __cpu_tlb_flags;
if (tlb_flag(TLB_DCLEAN))
asm("mcr p15, 0, %0, c7, c10, 1 @ flush_pmd"
: : "r" (pmd) : "cc");
if (tlb_flag(TLB_WB))
dsb();
}
static inline void clean_pmd_entry(pmd_t *pmd)
{
const unsigned int __tlb_flag = __cpu_tlb_flags;
if (tlb_flag(TLB_DCLEAN))
asm("mcr p15, 0, %0, c7, c10, 1 @ flush_pmd"
: : "r" (pmd) : "cc");
}
flush 의 경우에는
if (tlb_flag(TLB_WB)) dsb();
코드가 있어서 write back 캐시정책을 사용하는 경우에는
장벽을 사용해서 write buffer까지 비워버린다.
따라서 flush의 경우에는 캐시에서 지우게 되는 라인이 메모리에 쓰여지지 않고
clean의 경우에는 지우는 라인의 데이터가 write buffer에 남아있으므로
메모리에 쓰여지게 되는 결과가 나타나게 된다.
정리하면 다음과 같다.
Flush
- cache를 0으로 클리어
- cache를 0으로 클리어
- cache line의 유효비트를 0으로 셋팅
Clear
- cache의 dirty cache line을 메모리로 쓴 후 dirty bit를 0으로 셋팅
stubs_offset
entry-armv.S 파일에서는
stubs_start
...
stubs_end
vectors_start
...
vectors_end
순서로 코드가 작성되어 있는데 이를 trap_init() 함수에서는
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
로 복사한다.
0xffff0000 에 vectors_start 부분부터 복사해놓고
0xffff0200 에 stubs_start 부분부터 복사하게 된다.
따라서
stubs_end
stubs_start <--x--> vector_start 라고하면 stubs_offset 값은
vectors_start<--0x200--> stubs_start <--x--> stubs_end (stubs_offset의 위치)
로 바뀌게 된다.
stubs_offset 값은 __vectors_start + 0x200 - __stubs_start = 0x200 + x 이니깐
재배치한 후의 stubs_end와 같은 위치를 가리키게 된다.
따라서 상대주소로 점프하는 b 명령어가 정상적으로 작동한다.
stubs_start
...
stubs_end
vectors_start
...
vectors_end
순서로 코드가 작성되어 있는데 이를 trap_init() 함수에서는
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
로 복사한다.
0xffff0000 에 vectors_start 부분부터 복사해놓고
0xffff0200 에 stubs_start 부분부터 복사하게 된다.
따라서
stubs_end
stubs_start <--x--> vector_start 라고하면 stubs_offset 값은
vectors_start<--0x200--> stubs_start <--x--> stubs_end (stubs_offset의 위치)
로 바뀌게 된다.
stubs_offset 값은 __vectors_start + 0x200 - __stubs_start = 0x200 + x 이니깐
재배치한 후의 stubs_end와 같은 위치를 가리키게 된다.
따라서 상대주소로 점프하는 b 명령어가 정상적으로 작동한다.
j2me cldc source
여러가지 J2ME CLDC에 해당하는 프로젝트들이 있지만
요즘 검색해보아도 예전 SUN에서 나온 J2ME CLDC Spec에 해당하는
KVM의 소스는 찾기가 어렵다.
이에 예전에 받아두었던 KVM 소스를 링크한다.
첨부하는 KVM 소스는 전체가 C로만 구현되어 있는 대략 8,000 라인
정도의 초경량 VM이다.
실전에 이소스를 사용할 일은 별로 없겠지만 다음의 부분들은
이해하기에는 KVM은 핵심 부분만 간결하게
구현되어 있어서 매우 유용하다.
1. garbage collection
2. interpreter
3. KNI, native method
자바 가상 머신의 핵심부분은 KVM에도 거의 모두
구현되어 있다고 보아도 무방하다. 다만 JNI대신 KNI를
사용한다던가 6개의 핵심 패키지만 포함되어 있는 부분,
ROMJavaUNIX 기능을 사용하여 KVM에 핵심 패키지를 정적 링크하는
부분 등은 SPEC에 따르는 부분이므로 조금 다르다고 볼수 있다.
문서로는 java language specification 문서나 자바 가상 머신의 이해 책을 추천한다.
클래스의 구조와 native method, JNI, bytecode, interpreter의
작동방식을 이해하기에 두 문서는 매우 유용하다.
KVM SOURCE DOWNLOAD
요즘 검색해보아도 예전 SUN에서 나온 J2ME CLDC Spec에 해당하는
KVM의 소스는 찾기가 어렵다.
이에 예전에 받아두었던 KVM 소스를 링크한다.
첨부하는 KVM 소스는 전체가 C로만 구현되어 있는 대략 8,000 라인
정도의 초경량 VM이다.
실전에 이소스를 사용할 일은 별로 없겠지만 다음의 부분들은
이해하기에는 KVM은 핵심 부분만 간결하게
구현되어 있어서 매우 유용하다.
1. garbage collection
2. interpreter
3. KNI, native method
자바 가상 머신의 핵심부분은 KVM에도 거의 모두
구현되어 있다고 보아도 무방하다. 다만 JNI대신 KNI를
사용한다던가 6개의 핵심 패키지만 포함되어 있는 부분,
ROMJavaUNIX 기능을 사용하여 KVM에 핵심 패키지를 정적 링크하는
부분 등은 SPEC에 따르는 부분이므로 조금 다르다고 볼수 있다.
문서로는 java language specification 문서나 자바 가상 머신의 이해 책을 추천한다.
클래스의 구조와 native method, JNI, bytecode, interpreter의
작동방식을 이해하기에 두 문서는 매우 유용하다.
KVM SOURCE DOWNLOAD
lucene의 실행 script
Lucene 소스를 다운받아 보면 소스와 라이브러리, Jar 파일만 들어있기
때문에 처음접하는 사람의 경우 어떻게 시작해야 할지 당황하기 쉽다.
lucene의 자매품 같은 프로젝트로 nutch가 있는데
nutch에는 bin 폴더 밑에 "nutch"라는 실행 스크립트가 들어있다.
이를 수정해서 lucene용 스크립트로 사용하면 많은 수정없이
lucene에 맞게 사용할수 있다.
다음은 nutch 스크립트를 수정해서 만든 lucene 스크립트이다.
스크립트를 사용하려면 lucene폴더 하에 bin 폴더를 만들고
스크립트를 lucene이라는 이름으로 저장하고 실행하면 된다.
우선 실행하는 방법을 보자.
bin/lucene IndexFiles [Option]과 같이 간단하게 실행할수 있다.
보면 알겠지만 스크립트에는 contrib와 기타 jar에 포함되어 있는
모든 main을 포함하는 클래스를 포함시켰다.
스크립트의 소스는 다음과 같다.
#!/bin/bash
if [ $# = 0 ]; then
echo "Usage: lucene COMMAND"
echo "where COMMAND is one of:"
echo "DeleteFiles"
echo "IndexFiles"
echo "IndexHTML"
echo "IndexTrec"
echo "IndexPPT"
echo "SearchFiles"
echo "HTMLParseTest"
echo "PorterStemmer"
echo "CheckIndex"
echo "IndexReader"
echo "QueryParser"
echo "--------------- contrib ----------------"
echo "PatternParser"
echo "TernaryTree"
echo "Benchmark"
echo "precisionrecall"
echo "EvaluationTrec"
echo "programSample"
echo "QueryDriver"
echo "QualityQueriesFinder"
echo "ExtractReuters"
echo "ExtractWikipedia"
echo "SanityLoadLibrary"
echo "FieldTermStack"
echo "Lucli"
echo "FieldNormModifier"
echo "IndexSplitter"
echo "MultiPassIndexSplitter"
echo "HighFreqTerms"
echo "IndexMergeTool"
echo "PrecedenceQueryParser"
echo "MoreLikeThis"
echo "RemoteSearchable"
echo "TestRemoteSort"
echo "SnowballTestApp"
echo "GeoHashUtils"
echo "ListSearcherSimulater"
echo "SynExpand"
echo "SynLookup"
echo "Syns2Index"
echo "or"
echo " CLASSNAME run the class named CLASSNAME"
exit 1
fi
# get arguments
COMMAND=$1
shift
# some directories
THIS_DIR=`dirname "$THIS"`
#LUCENE_HOME=`cd "$THIS_DIR/.." ; pwd`
LUCENE_HOME=`echo $LUCENE_HOME`
# some Java parameters
if [ "$LUCENE_JAVA_HOME" != "" ]; then
#echo "run java in $LUCENE_JAVA_HOME"
JAVA_HOME=$LUCENE_JAVA_HOME
fi
if [ "$JAVA_HOME" = "" ]; then
echo "Error: JAVA_HOME is not set."
exit 1
fi
JAVA=$JAVA_HOME/bin/java
JAVA_HEAP_MAX=-Xmx1000m
# check envvars which might override default args
if [ "$LUCENE_HEAPSIZE" != "" ]; then
#echo "run with heapsize $LUCENE_HEAPSIZE"
JAVA_HEAP_MAX="-Xmx""$LUCENE_HEAPSIZE""m"
#echo $JAVA_HEAP_MAX
fi
CLASSPATH=$LUCENE_HOME/build/lucene-core-3.0.1-dev.jar:$LUCENE_HOME/build/lucene-demos-3.0.1-dev.jar
CLASSPATH=${CLASSPATH}:$JAVA_HOME/lib/tools.jar
#CLASSPATH=${CLASSPATH}:$LUCENE_HOME/build/classes
# add contrib to classpath
#for f in $LUCENE_HOME/build/lib-contrib/*.jar; do
# CLASSPATH=${CLASSPATH}:$f;
#done
# add libs to CLASSPATH
for f in $LUCENE_HOME/lib/*.jar; do
CLASSPATH=${CLASSPATH}:$f;
done
if [ "x$JAVA_LIBRARY_PATH" != "x" ]; then
LUCENE_OPTS="$LUCENE_OPTS -Djava.library.path=$JAVA_LIBRARY_PATH"
fi
# figure out which class to run
if [ "$COMMAND" = "DeleteFiles" ] ; then
CLASS=org.apache.lucene.demo.DeleteFiles
elif [ "$COMMAND" = "IndexFiles" ] ; then
CLASS=org.apache.lucene.demo.IndexFiles
elif [ "$COMMAND" = "IndexHTML" ] ; then
CLASS=org.apache.lucene.demo.IndexHTML
elif [ "$COMMAND" = "IndexTrec" ] ; then
CLASS=kr.ac.kaist.demo.IndexTrec
#CLASS=org.apache.lucene.demo.IndexTrec
elif [ "$COMMAND" = "SearchFiles" ] ; then
CLASS=kr.ac.kaist.demo.SearchFiles
elif [ "$COMMAND" = "HTMLParseTest" ] ; then
CLASS=org.apache.lucene.demo.html.Test
elif [ "$COMMAND" = "PorterStemmer" ] ; then
CLASS=org.apache.lucene.analysis.PorterStemmer
elif [ "$COMMAND" = "CheckIndex" ] ; then
CLASS=org.apache.lucene.index.CheckIndex
elif [ "$COMMAND" = "IndexReader" ] ; then
CLASS=org.apache.lucene.IndexReader
elif [ "$COMMAND" = "QueryParser" ] ; then
CLASS=org.apache.lucene.queryParser.QueryParser
elif [ "$COMMAND" = "English" ] ; then
CLASS=org.apache.lucene.util.English
elif [ "$COMMAND" = "PatternParser" ] ; then
CLASS=org.apache.lucene.analysis.compound.hyphenation.PatternParser
elif [ "$COMMAND" = "TernaryTree" ] ; then
CLASS=org.apache.lucene.analysis.compound.hyphenation.TernaryTree
elif [ "$COMMAND" = "Benchmark" ] ; then
CLASS=org.apache.lucene.benchmark.byTask.Benchmark
elif [ "$COMMAND" = "precisionrecall" ] ; then
CLASS=kr.ac.kaist.demo.PrecisionRecall
elif [ "$COMMAND" = "EvaluationTrec" ] ; then
CLASS=kr.ac.kaist.demo.EvaluationTrec
elif [ "$COMMAND" = "programSample" ] ; then
CLASS=org.apache.lucene.benchmark.byTask.programmatic.Sample
elif [ "$COMMAND" = "QueryDriver" ] ; then
CLASS=org.apache.lucene.benchmark.quality.trec.QueryDriver
elif [ "$COMMAND" = "QualityQueriesFinder" ] ; then
CLASS=org.apache.lucene.benchmark.quality.utils.QualityQueriesFinder
elif [ "$COMMAND" = "ExtractReuters" ] ; then
CLASS=org.apache.lucene.benchmark.utils.ExtractWikipedia
elif [ "$COMMAND" = "ExtractWikipedia" ] ; then
CLASS=org.apache.lucene.benchmark.utils.ExtractWikipedia
elif [ "$COMMAND" = "SanityLoadLibrary" ] ; then
CLASS=org.apache.lucene.store.db.SanityLoadLibrary
elif [ "$COMMAND" = "FieldTermStack" ] ; then
CLASS=org.apache.lucene.search.vectorhighlight.FieldTermStack
elif [ "$COMMAND" = "Lucli" ] ; then
CLASS=lucli.Lucli
elif [ "$COMMAND" = "FieldNormModifier" ] ; then
CLASS=org.apache.lucene.index.FieldNormModifier
elif [ "$COMMAND" = "IndexSplitter" ] ; then
CLASS=org.apache.lucene.index.IndexSplitter
elif [ "$COMMAND" = "MultiPassIndexSplitter" ] ; then
CLASS=org.apache.lucene.index.MultiPassIndexSplitter
elif [ "$COMMAND" = "HighFreqTerms" ] ; then
CLASS=org.apache.lucene.misc.HighFreqTerms
elif [ "$COMMAND" = "IndexMergeTool" ] ; then
CLASS=org.apache.lucene.misc.IndexMergeTool
elif [ "$COMMAND" = "PrecedenceQueryParser" ] ; then
CLASS=org.apache.lucene.
elif [ "$COMMAND" = "MoreLikeThis" ] ; then
CLASS=org.apache.lucene.search.similar.MoreLikeThis
elif [ "$COMMAND" = "RemoteSearchable" ] ; then
CLASS=org.apache.lucene.search.RemoteSearchable
elif [ "$COMMAND" = "TestRemoteSort" ] ; then
CLASS=org.apache.lucene.search.TestRemoteSort
elif [ "$COMMAND" = "SnowballTestApp" ] ; then
CLASS=org.tartarus.snowball.TestApp
elif [ "$COMMAND" = "GeoHashUtils" ] ; then
CLASS=org.apache.lucene.spatial.geohash.GeoHashUtils
elif [ "$COMMAND" = "ListSearcherSimulater" ] ; then
CLASS=org.apache.lucene.swing.models.ListSearcherSimulator
elif [ "$COMMAND" = "SynExpand" ] ; then
CLASS=org.apache.lucene.wordnet.SynExpand
elif [ "$COMMAND" = "SynLookup" ] ; then
CLASS=org.apache.lucene.wordnet.SynLookup
elif [ "$COMMAND" = "Syns2Index" ] ; then
CLASS=org.apache.lucene.wordnet.Syns2Index
else
CLASS=$COMMAND
fi
exec "$JAVA" $JAVA_HEAP_MAX $LUCENE_OPTS -cp "$CLASSPATH" $CLASS "$@"
때문에 처음접하는 사람의 경우 어떻게 시작해야 할지 당황하기 쉽다.
lucene의 자매품 같은 프로젝트로 nutch가 있는데
nutch에는 bin 폴더 밑에 "nutch"라는 실행 스크립트가 들어있다.
이를 수정해서 lucene용 스크립트로 사용하면 많은 수정없이
lucene에 맞게 사용할수 있다.
다음은 nutch 스크립트를 수정해서 만든 lucene 스크립트이다.
스크립트를 사용하려면 lucene폴더 하에 bin 폴더를 만들고
스크립트를 lucene이라는 이름으로 저장하고 실행하면 된다.
우선 실행하는 방법을 보자.
bin/lucene IndexFiles [Option]과 같이 간단하게 실행할수 있다.
보면 알겠지만 스크립트에는 contrib와 기타 jar에 포함되어 있는
모든 main을 포함하는 클래스를 포함시켰다.
스크립트의 소스는 다음과 같다.
#!/bin/bash
if [ $# = 0 ]; then
echo "Usage: lucene COMMAND"
echo "where COMMAND is one of:"
echo "DeleteFiles"
echo "IndexFiles"
echo "IndexHTML"
echo "IndexTrec"
echo "IndexPPT"
echo "SearchFiles"
echo "HTMLParseTest"
echo "PorterStemmer"
echo "CheckIndex"
echo "IndexReader"
echo "QueryParser"
echo "--------------- contrib ----------------"
echo "PatternParser"
echo "TernaryTree"
echo "Benchmark"
echo "precisionrecall"
echo "EvaluationTrec"
echo "programSample"
echo "QueryDriver"
echo "QualityQueriesFinder"
echo "ExtractReuters"
echo "ExtractWikipedia"
echo "SanityLoadLibrary"
echo "FieldTermStack"
echo "Lucli"
echo "FieldNormModifier"
echo "IndexSplitter"
echo "MultiPassIndexSplitter"
echo "HighFreqTerms"
echo "IndexMergeTool"
echo "PrecedenceQueryParser"
echo "MoreLikeThis"
echo "RemoteSearchable"
echo "TestRemoteSort"
echo "SnowballTestApp"
echo "GeoHashUtils"
echo "ListSearcherSimulater"
echo "SynExpand"
echo "SynLookup"
echo "Syns2Index"
echo "or"
echo " CLASSNAME run the class named CLASSNAME"
exit 1
fi
# get arguments
COMMAND=$1
shift
# some directories
THIS_DIR=`dirname "$THIS"`
#LUCENE_HOME=`cd "$THIS_DIR/.." ; pwd`
LUCENE_HOME=`echo $LUCENE_HOME`
# some Java parameters
if [ "$LUCENE_JAVA_HOME" != "" ]; then
#echo "run java in $LUCENE_JAVA_HOME"
JAVA_HOME=$LUCENE_JAVA_HOME
fi
if [ "$JAVA_HOME" = "" ]; then
echo "Error: JAVA_HOME is not set."
exit 1
fi
JAVA=$JAVA_HOME/bin/java
JAVA_HEAP_MAX=-Xmx1000m
# check envvars which might override default args
if [ "$LUCENE_HEAPSIZE" != "" ]; then
#echo "run with heapsize $LUCENE_HEAPSIZE"
JAVA_HEAP_MAX="-Xmx""$LUCENE_HEAPSIZE""m"
#echo $JAVA_HEAP_MAX
fi
CLASSPATH=$LUCENE_HOME/build/lucene-core-3.0.1-dev.jar:$LUCENE_HOME/build/lucene-demos-3.0.1-dev.jar
CLASSPATH=${CLASSPATH}:$JAVA_HOME/lib/tools.jar
#CLASSPATH=${CLASSPATH}:$LUCENE_HOME/build/classes
# add contrib to classpath
#for f in $LUCENE_HOME/build/lib-contrib/*.jar; do
# CLASSPATH=${CLASSPATH}:$f;
#done
# add libs to CLASSPATH
for f in $LUCENE_HOME/lib/*.jar; do
CLASSPATH=${CLASSPATH}:$f;
done
if [ "x$JAVA_LIBRARY_PATH" != "x" ]; then
LUCENE_OPTS="$LUCENE_OPTS -Djava.library.path=$JAVA_LIBRARY_PATH"
fi
# figure out which class to run
if [ "$COMMAND" = "DeleteFiles" ] ; then
CLASS=org.apache.lucene.demo.DeleteFiles
elif [ "$COMMAND" = "IndexFiles" ] ; then
CLASS=org.apache.lucene.demo.IndexFiles
elif [ "$COMMAND" = "IndexHTML" ] ; then
CLASS=org.apache.lucene.demo.IndexHTML
elif [ "$COMMAND" = "IndexTrec" ] ; then
CLASS=kr.ac.kaist.demo.IndexTrec
#CLASS=org.apache.lucene.demo.IndexTrec
elif [ "$COMMAND" = "SearchFiles" ] ; then
CLASS=kr.ac.kaist.demo.SearchFiles
elif [ "$COMMAND" = "HTMLParseTest" ] ; then
CLASS=org.apache.lucene.demo.html.Test
elif [ "$COMMAND" = "PorterStemmer" ] ; then
CLASS=org.apache.lucene.analysis.PorterStemmer
elif [ "$COMMAND" = "CheckIndex" ] ; then
CLASS=org.apache.lucene.index.CheckIndex
elif [ "$COMMAND" = "IndexReader" ] ; then
CLASS=org.apache.lucene.IndexReader
elif [ "$COMMAND" = "QueryParser" ] ; then
CLASS=org.apache.lucene.queryParser.QueryParser
elif [ "$COMMAND" = "English" ] ; then
CLASS=org.apache.lucene.util.English
elif [ "$COMMAND" = "PatternParser" ] ; then
CLASS=org.apache.lucene.analysis.compound.hyphenation.PatternParser
elif [ "$COMMAND" = "TernaryTree" ] ; then
CLASS=org.apache.lucene.analysis.compound.hyphenation.TernaryTree
elif [ "$COMMAND" = "Benchmark" ] ; then
CLASS=org.apache.lucene.benchmark.byTask.Benchmark
elif [ "$COMMAND" = "precisionrecall" ] ; then
CLASS=kr.ac.kaist.demo.PrecisionRecall
elif [ "$COMMAND" = "EvaluationTrec" ] ; then
CLASS=kr.ac.kaist.demo.EvaluationTrec
elif [ "$COMMAND" = "programSample" ] ; then
CLASS=org.apache.lucene.benchmark.byTask.programmatic.Sample
elif [ "$COMMAND" = "QueryDriver" ] ; then
CLASS=org.apache.lucene.benchmark.quality.trec.QueryDriver
elif [ "$COMMAND" = "QualityQueriesFinder" ] ; then
CLASS=org.apache.lucene.benchmark.quality.utils.QualityQueriesFinder
elif [ "$COMMAND" = "ExtractReuters" ] ; then
CLASS=org.apache.lucene.benchmark.utils.ExtractWikipedia
elif [ "$COMMAND" = "ExtractWikipedia" ] ; then
CLASS=org.apache.lucene.benchmark.utils.ExtractWikipedia
elif [ "$COMMAND" = "SanityLoadLibrary" ] ; then
CLASS=org.apache.lucene.store.db.SanityLoadLibrary
elif [ "$COMMAND" = "FieldTermStack" ] ; then
CLASS=org.apache.lucene.search.vectorhighlight.FieldTermStack
elif [ "$COMMAND" = "Lucli" ] ; then
CLASS=lucli.Lucli
elif [ "$COMMAND" = "FieldNormModifier" ] ; then
CLASS=org.apache.lucene.index.FieldNormModifier
elif [ "$COMMAND" = "IndexSplitter" ] ; then
CLASS=org.apache.lucene.index.IndexSplitter
elif [ "$COMMAND" = "MultiPassIndexSplitter" ] ; then
CLASS=org.apache.lucene.index.MultiPassIndexSplitter
elif [ "$COMMAND" = "HighFreqTerms" ] ; then
CLASS=org.apache.lucene.misc.HighFreqTerms
elif [ "$COMMAND" = "IndexMergeTool" ] ; then
CLASS=org.apache.lucene.misc.IndexMergeTool
elif [ "$COMMAND" = "PrecedenceQueryParser" ] ; then
CLASS=org.apache.lucene.
elif [ "$COMMAND" = "MoreLikeThis" ] ; then
CLASS=org.apache.lucene.search.similar.MoreLikeThis
elif [ "$COMMAND" = "RemoteSearchable" ] ; then
CLASS=org.apache.lucene.search.RemoteSearchable
elif [ "$COMMAND" = "TestRemoteSort" ] ; then
CLASS=org.apache.lucene.search.TestRemoteSort
elif [ "$COMMAND" = "SnowballTestApp" ] ; then
CLASS=org.tartarus.snowball.TestApp
elif [ "$COMMAND" = "GeoHashUtils" ] ; then
CLASS=org.apache.lucene.spatial.geohash.GeoHashUtils
elif [ "$COMMAND" = "ListSearcherSimulater" ] ; then
CLASS=org.apache.lucene.swing.models.ListSearcherSimulator
elif [ "$COMMAND" = "SynExpand" ] ; then
CLASS=org.apache.lucene.wordnet.SynExpand
elif [ "$COMMAND" = "SynLookup" ] ; then
CLASS=org.apache.lucene.wordnet.SynLookup
elif [ "$COMMAND" = "Syns2Index" ] ; then
CLASS=org.apache.lucene.wordnet.Syns2Index
else
CLASS=$COMMAND
fi
exec "$JAVA" $JAVA_HEAP_MAX $LUCENE_OPTS -cp "$CLASSPATH" $CLASS "$@"
2011년 7월 8일 금요일
J2ME phoneme, dalvik, apache harmony
Dalvik은 안드로이드 프레임워크에 포함된 가상머신이다.
웹상에서 apache harmony와 dalvik과의 관련성에 대한 여러 글을 볼수 있는데
나는 apache harmony의 코드를 본적이 없어서 위의 주제에 대한
확인을 해보지는 못했다.
다만 sun 지금의 oracle사의 j2me 오픈소스 프로젝트인
phoneme와 dalvik의 코드는 분석을 해보았으며 상당한 유사성을 발견하였다.
두 프로젝트의 시작루틴은 다음과 같다.
왼쪽이 phoneme이고 오른쪽이 dalvik이다.
시작은 좀 다른듯 보이지만 phoneme의 경우 실제 시작은
위의 코드에서 보듯 ansiJavaMain 함수부터이다.
코드가 잘 보일지 모르겠는데 자세히 보면 상당히 유사하다.
변수명은 다르지만 선언된 구조체 JavaVM, JNIEnv, JavaVMInitArgs
일단 이렇게 3개의 구조체의 이름이 동일하다는 것을 확인할수 있다.
typedef const struct JNIInvokeInterface *JavaVM;
typedef const struct JNINativeInterface *JNIEnv;
typedef struct JavaVMInitArgs {
jint version;
jinit nOptions;
JavaVMOption *option;
jboolean ignoreUnrecognized;
} JavaVMInitArgs;
JavaVM, JNIEnv, JavaVMInitArgs은 실제로 두 프로젝트 모두
위와 같은 코드로 되어 있다.
추가적으로 JNINativeInterface, JNIInvokeInterface 구조체를 비교해보자.
역시나 왼쪽이 phoneme project, 오른쪽이 dalvik project이다.
약간의 차이를 제외하고는 구조체가 거의 동일하다. 이정도면 우연히 일치했다고
보기는 정말로 힘들어 보인다.
기타 main에서 호출하는 함수의 이름과 전체적인 과정도 상당히 유사하나 이글의
목적은 단순히 phoneme와 dalvik이 서로 관련이 있음을 알리는 목적이므로 이 정도에서
충분하리라 본다. 궁금하신 분들은 직접 코드를 비교해 보시라.
개인적인 생각으로는 코드의 유사성이 다음의 3가지 경우중 하나에서
기인한게 아닐까 생각한다.
1. dalvik이 직접적으로 phoneme의 코드를 참조했다.
2. phoneme를 참조한 다른 오픈소스의 코드를 dalvik이 참조했다.
3. dalvik과 phoneme가 공통적으로 참조한 다른 프로젝트가 존재한다.
4. 기막힌 우연이다.
4의 경우는 확률이 극히 낮으므로 제외하고 생각해볼때
일단 2,3의 경우가 유력해 보인다. 1의 경우가 아니라고 생각하는 이유는 검색을
해보아도 phoneme 프로젝트와 dalvik의 유사성과 관련한 글을 거의 찾기가 어렵기
때문이다. (물론 1의 경우일 가능성도 없지는 않다. )
3의 경우라면 그 다른 프로젝트가 apache harmony일수도 있으나
phoneme project는 java 언어 및 jvm을 개발한 sun에서 시작한 오픈소스이며
harmony는 sun jvm의 reference implementation이므로 좀 이치에 맞지 않아 보이고
따라서 필자는 2의 경우로 생각하며 이 중간고리가 웹상의 논란거리가 되는
프로젝트가 harmony 일수도 있다고 본다. 이를 확인해 보려면 harmony의 소스를
분석해 보아야만 하기에 일단은 여기에서 줄인다.
ps. 추가적으로 phonme와 dalvik은 interpreter 부분의 코드를 제외하고는
상당부분이 거의 동일하다고 보면된다. 이부분은 꽤 길고 어려우므로
다음 글에 따로 정리한다.
웹상에서 apache harmony와 dalvik과의 관련성에 대한 여러 글을 볼수 있는데
나는 apache harmony의 코드를 본적이 없어서 위의 주제에 대한
확인을 해보지는 못했다.
다만 sun 지금의 oracle사의 j2me 오픈소스 프로젝트인
phoneme와 dalvik의 코드는 분석을 해보았으며 상당한 유사성을 발견하였다.
두 프로젝트의 시작루틴은 다음과 같다.
왼쪽이 phoneme이고 오른쪽이 dalvik이다.
시작은 좀 다른듯 보이지만 phoneme의 경우 실제 시작은
위의 코드에서 보듯 ansiJavaMain 함수부터이다.
코드가 잘 보일지 모르겠는데 자세히 보면 상당히 유사하다.
변수명은 다르지만 선언된 구조체 JavaVM, JNIEnv, JavaVMInitArgs
일단 이렇게 3개의 구조체의 이름이 동일하다는 것을 확인할수 있다.
typedef const struct JNIInvokeInterface *JavaVM;
typedef const struct JNINativeInterface *JNIEnv;
typedef struct JavaVMInitArgs {
jint version;
jinit nOptions;
JavaVMOption *option;
jboolean ignoreUnrecognized;
} JavaVMInitArgs;
JavaVM, JNIEnv, JavaVMInitArgs은 실제로 두 프로젝트 모두
위와 같은 코드로 되어 있다.
추가적으로 JNINativeInterface, JNIInvokeInterface 구조체를 비교해보자.
역시나 왼쪽이 phoneme project, 오른쪽이 dalvik project이다.
약간의 차이를 제외하고는 구조체가 거의 동일하다. 이정도면 우연히 일치했다고
보기는 정말로 힘들어 보인다.
기타 main에서 호출하는 함수의 이름과 전체적인 과정도 상당히 유사하나 이글의
목적은 단순히 phoneme와 dalvik이 서로 관련이 있음을 알리는 목적이므로 이 정도에서
충분하리라 본다. 궁금하신 분들은 직접 코드를 비교해 보시라.
개인적인 생각으로는 코드의 유사성이 다음의 3가지 경우중 하나에서
기인한게 아닐까 생각한다.
1. dalvik이 직접적으로 phoneme의 코드를 참조했다.
2. phoneme를 참조한 다른 오픈소스의 코드를 dalvik이 참조했다.
3. dalvik과 phoneme가 공통적으로 참조한 다른 프로젝트가 존재한다.
4. 기막힌 우연이다.
4의 경우는 확률이 극히 낮으므로 제외하고 생각해볼때
일단 2,3의 경우가 유력해 보인다. 1의 경우가 아니라고 생각하는 이유는 검색을
해보아도 phoneme 프로젝트와 dalvik의 유사성과 관련한 글을 거의 찾기가 어렵기
때문이다. (물론 1의 경우일 가능성도 없지는 않다. )
3의 경우라면 그 다른 프로젝트가 apache harmony일수도 있으나
phoneme project는 java 언어 및 jvm을 개발한 sun에서 시작한 오픈소스이며
harmony는 sun jvm의 reference implementation이므로 좀 이치에 맞지 않아 보이고
따라서 필자는 2의 경우로 생각하며 이 중간고리가 웹상의 논란거리가 되는
프로젝트가 harmony 일수도 있다고 본다. 이를 확인해 보려면 harmony의 소스를
분석해 보아야만 하기에 일단은 여기에서 줄인다.
ps. 추가적으로 phonme와 dalvik은 interpreter 부분의 코드를 제외하고는
상당부분이 거의 동일하다고 보면된다. 이부분은 꽤 길고 어려우므로
다음 글에 따로 정리한다.
피드 구독하기:
글 (Atom)








