02.Oracle/DataBase2012. 9. 21. 05:23
반응형

WITH TEST AS
(
select 'A' grade, 10 cnt from dual union all
select 'A' grade, 20 cnt from dual union all
select 'A' grade, 15 cnt from dual union all
select 'B' grade, 20 from dual union all
select 'B' grade, 30 from dual union all
select 'D' grade, 15 from dual union all
select 'F' grade, 10 from dual
)
SELECT
grade 등급,
cnt 학생수,
sum(cnt) over () 갯수,
row_number() over(partition by grade order by cnt) 로넘,
rank() over(partition by grade order by cnt) 랭크,
round((cnt / sum(cnt) over ())*100,2) 구성비,
sum(cnt) over (partition by grade order by grade) 누적학생수,
sum(cnt) over (partition by grade,cnt order by grade) 그레카운,
sum(cnt) over (order by grade) 누적,
round((sum(cnt) over (order by grade)/sum(cnt) over ())*100,2) 누적구성비
FROM TEST;

/*

rank() over(partition by grade order by cnt) 랭크,

표현식 over (partition by 컬럼1 order by 컬럼2)

이 의미는

"(컬럼1값이 같은놈들로 묶은것을 컬럼2로 정렬한) 각 파티션별로 표현식을 수행해준다."

*/

복잡하군... :(

[출처] Oracle over() 구문|작성자 18061975

 

Posted by 1010
02.Oracle/DataBase2012. 9. 21. 03:19
반응형

오랔믈 pivot 기능

SELECT TO_CHAR(rgs_dt,'YYYYMMDD'),
              'TA_IPT_ICG_MNFT_MST' AS title,
              COUNT(mrn)            AS cnt
         FROM TA_IPT_ICG_MNFT_MST
        WHERE USE_FG = 'S'
        GROUP BY TO_CHAR(rgs_dt,'YYYYMMDD')
           UNION
       SELECT TO_CHAR(rgs_dt,'YYYYMMDD'),
              'TA_ICG_MNFT_MST' AS title,
              COUNT(mrn)        AS cnt
         FROM TA_ICG_MNFT_MST
        WHERE USE_FG = 'S'
        GROUP BY TO_CHAR(rgs_dt,'YYYYMMDD')

 

 

 

 

SELECT *
  FROM
       (SELECT TO_CHAR(rgs_dt,'YYYYMMDD'),
              'TA_IPT_ICG_MNFT_MST' AS title,
              COUNT(mrn)            AS cnt
         FROM TA_IPT_ICG_MNFT_MST
        WHERE USE_FG = 'S'
        GROUP BY TO_CHAR(rgs_dt,'YYYYMMDD')
           UNION
       SELECT TO_CHAR(rgs_dt,'YYYYMMDD'),
              'TA_ICG_MNFT_MST' AS title,
              COUNT(mrn)        AS cnt
         FROM TA_ICG_MNFT_MST
        WHERE USE_FG = 'S'
        GROUP BY TO_CHAR(rgs_dt,'YYYYMMDD')
       ) pivot (SUM(cnt) FOR title IN('TA_IPT_ICG_MNFT_MST','TA_ICG_MNFT_MST'))
ORDER BY 1

 

 

 

Posted by 1010
반응형

출처 : http://sbcoba.tistory.com/

 

요즘 ORM으로는 하이버네이트, JPA등 많이 사용하고 있으나, 역시 SI 쪽은 mybatis(ibatis)를 많이 사용된다.

문제는 mybatis는 xml로 sql을 관리하고 있는데 보통 조금 바꿀때 마다 서버를 재구동 시켜야 되는 문제가 된다.

시스템이 클 경우 재시작시 오랜 시간 걸리고 session 사용시 또 로그인을 해야 하는듯 개발의 흐름이 끊어지는 문제가 많이 발생한다.

예전에 ibatis를 사용 했을시에도 그런 부분이 많이 불편했었는데, 예전 대우정보시스템의 JCF 프레임워크에서 사용된다고 Refresh 되는 클래스 소스가 한번 공개 된적이 있었다. ( 몇년전인지 기억은 안나지만, 당시 인터넷 검색으로 찾았었다. )

그것이 버전이 문제인지 바로 사용이 안되어서 커스터마이징하고 사용을 잘사용 했었다.

그런데 지금 프로젝트가 mybatis로 진행하기 때문에 예전과 같은 불편함이 또 생기게 되었는데, 이 번에는 그 소스를 mybatis에 맞도로 커스터마이징 하기로 했다.

일단 사전 조건은

JDK 1.5 이상, Spring, mybatis, spring-mybatis 라이브러리가 설치되어 있는 환경에서만 된다.


일단 기존 Spring 에서 mybatis 설정을 보겠다.

보통 sqlSessionFactory를 이렇게 설정 한다.

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" p:mapperLocations="classpath*:패키지경로/**/mapper.xml" p:configLocation="classpath:/MapperConfig.xml" p:dataSource-ref="dataSource"/>

classpath*:패키지경로/**/mapper.xml <- 이부분이 재로딩될 xml 파일 경로

이부분에서 굵게 표시한 class 부분만 새로 만든 클래스로 바꾸면 모든게 해결된다.

<bean id="sqlSessionFactory" class="패키지경로.RefreshableSqlSessionFactoryBean" p:mapperLocations="classpath*:패키지경로/**/mapper.xml" p:configLocation="classpath:/MapperConfig.xml" p:dataSource-ref="dataSource" />

RefreshableSqlSessionFactoryBean.java

import java.io.IOException;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.Timer;

import java.util.TimerTask;


import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.apache.ibatis.session.SqlSessionFactory;

import org.mybatis.spring.SqlSessionFactoryBean;

import org.springframework.beans.factory.DisposableBean;

import org.springframework.core.io.Resource;


import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantReadWriteLock;


/**

* mybatis mapper 자동 감지 후 자동으로 서버 재시작이 필요 없이 반영

*

* @author

*

*/

public class RefreshableSqlSessionFactoryBean extends SqlSessionFactoryBean implements DisposableBean {


private static final Log log = LogFactory .getLog(RefreshableSqlSessionFactoryBean.class);


private SqlSessionFactory proxy;

private int interval = 500;


private Timer timer;

private TimerTask task;


private Resource[] mapperLocations;


/**

* 파일 감시 쓰레드가 실행중인지 여부.

*/

private boolean running = false;


private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

private final Lock r = rwl.readLock();

private final Lock w = rwl.writeLock();


public void setMapperLocations(Resource[] mapperLocations) {

super.setMapperLocations(mapperLocations);

this.mapperLocations = mapperLocations;

}


public void setInterval(int interval) {

this.interval = interval;

}


/**

*

* @throws Exception

*/

public void refresh() throws Exception {

if (log.isInfoEnabled()) {

log.info("refreshing sqlMapClient.");

}

w.lock();

try {

super.afterPropertiesSet();


} finally {

w.unlock();

}

}


/**

* 싱글톤 멤버로 SqlMapClient 원본 대신 프록시로 설정하도록 오버라이드.

*/

public void afterPropertiesSet() throws Exception {

super.afterPropertiesSet();


setRefreshable();

}


private void setRefreshable() {

proxy = (SqlSessionFactory) Proxy.newProxyInstance(

SqlSessionFactory.class.getClassLoader(),

new Class[] { SqlSessionFactory.class },

new InvocationHandler() {

public Object invoke(Object proxy, Method method,

Object[] args) throws Throwable {

// log.debug("method.getName() : " + method.getName());

return method.invoke(getParentObject(), args);

}

});


task = new TimerTask() {

private Map<Resource, Long> map = new HashMap<Resource, Long>();


public void run() {

if (isModified()) {

try {

refresh();

} catch (Exception e) {

log.error("caught exception", e);

}

}

}


private boolean isModified() {

boolean retVal = false;


if (mapperLocations != null) {

for (int i = 0; i < mapperLocations.length; i++) {

Resource mappingLocation = mapperLocations[i];

retVal |= findModifiedResource(mappingLocation);

}

}


return retVal;

}


private boolean findModifiedResource(Resource resource) {

boolean retVal = false;

List<String> modifiedResources = new ArrayList<String>();


try {

long modified = resource.lastModified();


if (map.containsKey(resource)) {

long lastModified = ((Long) map.get(resource))

.longValue();


if (lastModified != modified) {

map.put(resource, new Long(modified));

modifiedResources.add(resource.getDescription());

retVal = true;

}

} else {

map.put(resource, new Long(modified));

}

} catch (IOException e) {

log.error("caught exception", e);

}

if (retVal) {

if (log.isInfoEnabled()) {

log.info("modified files : " + modifiedResources);

}

}

return retVal;

}

};


timer = new Timer(true);

resetInterval();


}


private Object getParentObject() throws Exception {

r.lock();

try {

return super.getObject();


} finally {

r.unlock();

}

}


public SqlSessionFactory getObject() {

return this.proxy;

}


public Class<? extends SqlSessionFactory> getObjectType() {

return (this.proxy != null ? this.proxy.getClass()

: SqlSessionFactory.class);

}


public boolean isSingleton() {

return true;

}


public void setCheckInterval(int ms) {

interval = ms;


if (timer != null) {

resetInterval();

}

}


private void resetInterval() {

if (running) {

timer.cancel();

running = false;

}

if (interval > 0) {

timer.schedule(task, 0, interval);

running = true;

}

}


public void destroy() throws Exception {

timer.cancel();

}

}


만약에 재로딩 되는 시간을 바꾸고 싶으면

<bean id="sqlSessionFactory" class="패키지경로.RefreshableSqlSessionFactoryBean" p:mapperLocations="classpath*:kr/web/**/mapper.xml" :configLocation="classpath:/MapperConfig.xml" p:dataSource-ref="dataSource" p:interval="1000" />

p:interval="1000" 이부분을 수치를 정해주면된다. ( 디폴트는 500, 단위 ms )


이제 설정을 서버를 시작해서 위에 로케이션 해당하는 mapper.xml ( sql이 있는 xml , 설정에 따라 다름)에서

sql을 바꿔 보자 그리고 클라이언트에서 바뀐지 확인해보자

큰 문제가 없다면 반영될것이라고 생각된다.


아 단 운영 시스템에 사용은 보장 못합니다~ 개발시에서만 사용하세요~


이 소스는 예전에 인터넷에서 나돌던 RefreshableSqlMapClientFactoryBean 소스를 커스터마이징한 소스인데 문제가 있다면 연락주시길바랍니다.

 

Posted by 1010
56. Eclipse Etc...2012. 9. 20. 08:15
반응형

출처 : http://joke00.tistory.com/18 

자바_한글_api.part01.exe

자바_한글_api.part02.rar

자바_한글_api.part03.rar

 


1. 첨부된 파일을 다운받아 한 폴더에 넣습니다



2. 자바_한글_API_par01.exe 를 실행시킨후 저절로 api라는 이름으로 압축이 풀립니다.
그러면.... 이클립스가 설치된 폴더 안에 넣습니다.

난, C:\program files\ eclipse 폴더에 넣습니다. 뭐를? api 폴더를~


3. 이제 이클립스를 실행 시킵니다.

4. 이클립스 실행 후에 프로젝트 중 아무거나 하나 클릭해서, rt.jar 파일 찾는다.



5. properties 에 들어가게 되면
type filter text > Java source Attachment 가 있는데,
여기의 Location Path 부분을 지운다


6. Javadoc Location 에 가면 javadoc URL 설정부분에서....
아까 압축받아서 푼 API 를 넣어준 이클립스 경로를 브라우저 눌러서 찾아서 API/ 까지 등록



7. 자, 이제 원초적인 JAVA API 는 한글로 편히 볼 수 있다 ㅋㅋㅋ


 

Posted by 1010
01.JAVA/Java2012. 9. 20. 07:52
반응형

출처 : http://joke00.tistory.com/69

 

자바 책을 훑어보던 중.
Exception 관련해서 assertion 부분이 나왔다. ( 왜.. 예전엔 미처 몰랐을까;;;;)

assertion 은 디버깅시에 익셉션 에러 검증 구문으로 인용하기 쉽다.
throws 나 try ~ catch 블럭과 동일한 역할을 합니다.

사용법
---------------------------------------------------------------------------------------------
assert [ true or false 를 나타내는검증구문] : [검증에서 false 발생시 출력할 내용]
---------------------------------------------------------------------------------------------

1. 이클립스를 열어 테스트를 하나 만듭니다.



2. 해당 프로젝트를 선택 후 마우스 오른쪽을 누르면 properties 를 눌러 Run/Debug Settings 를 선택합니다.
해당 프로젝트가 보이네요~ edit 를 누릅니다



3. Arguments 탭으로 이동후 VM arguments 를 입력합니다.
-ea 는 assertion 실행
-ea:클래스명 : 해당 클래스만 assetion 을 실행
-ea:... : 현재 패키지 내에 있는 클래스들만 assertion 실행
-ea<package명> : 해당 package 명 내의 클래스들만 assetion 실행

-da 로 했을 경우에는 반대로 해당되는 경우에만 assertion 을 실행시키지 않음



4. ctrl + f11 을 눌러 실행을 시킵니다.
아름과 같은 익셉션 구문과 함께 어디서 익셉션이 났는지를 알려준답니다 ^^

Posted by 1010
56. Eclipse Etc.../Eclipse2012. 9. 20. 07:44
반응형

출처 : http://joke00.tistory.com/56

이클립스에서 개발하다 보면 interface 클래스를 많이 사용하게 되는데..
특히 스프링을 사용하거나 프레임 웍을 사용하다 보면 interface 클래스를 많이 쓰게 된다.
이때, 컨트롤을 누르고 메소드를 클릭하게 되면 interface 메소드로 가게 되있는데,
이 implementors 플러그 인은 말 그대로 해당 interface 가 아니라 interface 구현체인 implements 메소드를
찾아갈 수 있게끔 하는 플러그인이다.

꽤 유용할듯~

자, 이제 설치해 봅시다

URL : http://eclipse-tools.sourceforge.net/updates

1. 이클립스의 [help] - [Install New SoftWare] 를 선택합니다. (3.5 갈릴레오 기준)



2. 선택 후 next~



3. 이 플러그인은 다른것들과는 다른 accept 창이 나오니, 당황하지 마시고, 동의하고 next 넘어가면 됩니다.



4. 무지 빠른 속도로 install 되니, 어디 가지 마세요 ^^




5. 설치가 끝난 후 어김없이 뜹니다. "지금 당장 재부팅 하시꺼유?" YES!



6. 자, 한번 테스트 해 봅시다.

getData 라는 interface 메소드가 있는데, 이전 같으면 Ctrl + 누른후 마우스를 가져다 대면 interface 클래스로 이동했는데, 이번엔 선택하도록 나옵니다.

open Declaration -> interface 클래스의 메소드로 이동 ==> F3
open Implementation -> interface 를 implements 한 class 의 메소드로 이동 => Alt + F3



나 이거 캡쳐하느라 애 좀 먹었다규;;; -_-;;;;

단축키 이동이 불편하다면,
[Window] - [preference ] - [General] - [keys] 에서 재 등록 하시면 됩니다.




 

Posted by 1010
01.JAVA/Java2012. 9. 20. 07:03
반응형

Quick Start

Have you downloaded? Good. Now let’s get your first compiled spreadsheet up and running. I’ll show you how to…

  • create a spreadsheet defining a customized line item price computation,
  • make AFC compile it to Java classes,
  • use those classes in your application,
  • look at the generated code, and
  • save and reload the classes from a .jar file.

The Problem

This is a fictional example about finding the total price for a line item with

  • a base article price,
  • a count of items, and
  • the customer category (for automatic rebates).

We will flesh out the following bit of code:

// Compile price finding factory and strategy implementation from spreadsheet:
EngineBuilder builder = SpreadsheetCompiler.newEngineBuilder();
builder.loadSpreadsheet( new File( PATH, "CustomPriceFormula.xls" ) );
builder.setFactoryClass( PriceFinderFactory.class );
builder.bindAllByName();
Engine engine = builder.compile();
PriceFinderFactory factory = (PriceFinderFactory) engine.getComputationFactory();

// Use it to compute a line item price:
LineItem item = getCurrentLineItem();
PriceFinder priceFinder = factory.newInstance( item );
BigDecimal price = priceFinder.getPrice();

The Spreadsheet

Here’s the spreadsheet-defined formula our user wants the application to use:

A B C D E
1 Input Values
2 Article Price 500.00
3 Item Count 5
4 Customer Category C
5
6 Intermediate Values
7 Categories A B C D
8 Rebates 6% 4% 1% 0%
9 Effective Rebate =HLOOKUP(B4,B7:E8,2.0)
10 Base Price =B2*B3
11
12 Output Values
13 Price =B10*(1.0-B9)

Please create this spreadsheet now and save it somewhere under the name CustomPriceFormula.xls.

The Project

Create a new Java project for this demo application now. Add to it references to the following libraries you obtained from the download:

build/formulacompiler-runtime.jar
build/formulacompiler-compiler.jar
build/formulacompiler-spreadsheet.jar
build/formulacompiler-spreadsheet-excel-xls.jar
build/formulacompiler-decompiler.jar
build/lib/asm-x.y.jar
build/lib/asm-commons-x.y.jar
build/lib/jxl.jar
build/lib/jode-decompiler.jar

Then create a main class in it. Unless your IDE can find and organize imports automatically, you might also want to add these to your main class:

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.math.BigDecimal;

import org.formulacompiler.compiler.CompilerException;
import org.formulacompiler.compiler.SaveableEngine;
import org.formulacompiler.decompiler.ByteCodeEngineSource;
import org.formulacompiler.decompiler.FormulaDecompiler;
import org.formulacompiler.runtime.Engine;
import org.formulacompiler.runtime.EngineException;
import org.formulacompiler.runtime.FormulaRuntime;
import org.formulacompiler.spreadsheet.EngineBuilder;
import org.formulacompiler.spreadsheet.SpreadsheetCompiler;

The Interfaces

In essence, what AFC compiles from the spreadsheet is a computation strategy implementation. So we need the customary factory and doer interfaces that go with a strategy:

public static interface PriceFinder {
  BigDecimal getPrice();
}

public static interface PriceFinderFactory {
  PriceFinder newInstance( LineItem item );
}

Paste these directly into your main class (they are nested classes in this example, but AFC is just as happy with top-level classes).

We’ll also need the line item, which provides input data to the computation:

public static class LineItem {
  public BigDecimal getArticlePrice() { return BigDecimal.valueOf( 112.00 ); } 
  public int getItemCount() { return 10; }
  public String getCustomerCategory() { return "B"; }
}

It’s obviously a dummy. Paste it into the main class as well, together with the following dummy getter:

private LineItem getCurrentLineItem() {
  return new LineItem();
}

The Compilation

We’re ready to compile now. Add the following two methods, that I’ll explain shortly:

private SaveableEngine compile() throws FileNotFoundException, IOException, CompilerException, EngineException
{
  EngineBuilder builder = SpreadsheetCompiler.newEngineBuilder();
  builder.loadSpreadsheet( new File( PATH, "CustomPriceFormula.xls" ) );
  builder.setFactoryClass( PriceFinderFactory.class );
  builder.bindAllByName();
  return builder.compile();
}

private PriceFinderFactory factoryFor( Engine engine )
{
  return (PriceFinderFactory) engine.getComputationFactory();
}

Also add a constant for the path where you saved the spreadsheet. In my code, it’s:

public static final File PATH = new File( "src/test/data/org/formulacompiler/tutorials" );

Let’s go through this now:

  • First, we get a new engine builder. It gives us a simplified API onto AFC.
  • We tell the builder to load the spreadsheet you created earlier on. AFC detects the appropriate loader to use by the file’s extension. It currently supports Microsoft Excel (.xls) and OpenOffice Calc (.ods), and maybe others – check the release notes for details.
  • We inform the builder of our factory class. It can usually infer from this the input interface, LineItem, and the output interface, PriceFinder, by itself (if not, you can given them explicitly; you can then also omit the factory interface altogether).
  • We tell the builder to bind spreadsheet cells to our interface methods by name. In short, any cell named after a method on the input interface, LineItem, gets its value from that method in the compiled formula. A cell named after a method on the output interface, PriceFinder, is used to implement that method. (The binder is smart about dropping the get prefix on method names and is not case sensitive.)
  • But wait, we don’t have any cell names in this spreadsheet. What’s going on? AFC automatically creates cell names from row titles (string values in column A are applied as names for corresponding cells in column B) when a sheet has no cell names and you use bindAllByName().
  • That’s it. We tell the builder to compile the thing. It returns a so-called engine (which we’ll later use to save, reload, and decompile), but the most important method on the engine is the one we use on our second method: getComputationFactory().

The Computation

We now look at how the resulting price finder is used. Since AFC compiles spreadsheets to regular JVM classes, there’s no magic at all when using a precompiled computation:

private BigDecimal compute( PriceFinderFactory factory )
{
  PriceFinder priceFinder = factory.newInstance( getCurrentLineItem() );
  return priceFinder.getPrice();
}

So let’s make this runnable:

public static void main( String[] args ) throws Exception
{
  QuickStart app = new QuickStart();
  SaveableEngine engine = app.compile();
  PriceFinderFactory factory = app.factoryFor( engine );
  BigDecimal price = app.compute( factory );
  System.out.println( "The result is " + price );
}

Go ahead. Run it.

The Code

Would you also like to know just what exactly the generated PriceFinder implementation does? You can. AFC wraps a nifty external library, Jode, to decompile generated code to plain Java source again for just this purpose. Let’s use this:

private void decompile( SaveableEngine engine ) throws Exception
{
  ByteCodeEngineSource source = FormulaDecompiler.decompile( engine );
  source.saveTo( new File( "temp/test/decompiled/quickstart" ) );
}

You can change the output folder, of course. Now add the following at the end of the main method:

app.decompile( engine );

Run it again. Then look into the output folder. You should find the following there. First, the generated computation:

package org.formulacompiler.gen;
import java.math.BigDecimal;

import org.formulacompiler.runtime.Computation;
import org.formulacompiler.runtime.FormulaException;
import org.formulacompiler.runtime.internal.Environment;
import org.formulacompiler.runtime.internal.RuntimeDouble_v2;
import org.formulacompiler.runtime.internal.Runtime_v2;
import org.formulacompiler.tutorials.QuickStart;

final class $Root implements Computation, QuickStart.PriceFinder
{
    private final QuickStart.LineItem $inputs;
    final Environment $environment;
    private String[] $constarr$0;
    
    $Root(QuickStart.LineItem lineitem, Environment environment) {
        $environment = environment;
        $inputs = lineitem;
    }
    
    final double get$0() {
        return (get$1() * get$2()
                * (1.0 - $idx$0(Runtime_v2.fun_MATCH_Ascending(get$3(),
                                                               $constarr$0(),
                                                               $environment)
                                - 1)));
    }
    
    public final BigDecimal getPrice() {
        return BigDecimal.valueOf(Runtime_v2.checkDouble(get$0()));
    }
    
    final String[] $constarr$0() {
        if ($constarr$0 == null)
            $constarr$0 = new String[] { "A", "B", "C", "D" };
        return $constarr$0;
    }
    
    final double $idx$0(int i) {
        switch (i) {
        case 0:
            return 0.06;
        case 1:
            return 0.04;
        case 2:
            return 0.01;
        case 3:
            return 0.0;
        default:
            throw new FormulaException
                      ("#VALUE/REF! because index is out of range in INDEX");
        }
    }
    
    final double get$1() {
        return RuntimeDouble_v2.numberToNum($inputs.getArticlePrice());
    }
    
    final double get$2() {
        return (double) $inputs.getItemCount();
    }
    
    final String get$3() {
        return Runtime_v2.stringFromString($inputs.getCustomerCategory());
    }
}

Second, it’s corresponding factory:

package org.formulacompiler.gen;
import org.formulacompiler.runtime.Computation;
import org.formulacompiler.runtime.ComputationFactory;
import org.formulacompiler.runtime.internal.Environment;
import org.formulacompiler.tutorials.QuickStart;

public final class $Factory
    implements ComputationFactory, QuickStart.PriceFinderFactory
{
    private final Environment $environment;
    
    public $Factory(Environment environment) {
        $environment = environment;
    }
    
    public final Computation newComputation(Object object) {
        return new $Root((QuickStart.LineItem) object, $environment);
    }
    
    public final QuickStart.PriceFinder newInstance
        (QuickStart.LineItem lineitem) {
        return new $Root(lineitem, $environment);
    }
}

The Runtime

Computations compiled by AFC are plain compiled Java classes. They rely only on a single small runtime library, formulacompiler-runtime.jar. So it’s good practice to simply save them to a .jar file and reuse them from there across application starts (or to even split the compiling application from the using application). However, they do require a special classloader. AFC therefore provides special methods to save and load engines properly.

First, let’s save our engine:

private void save( SaveableEngine engine ) throws Exception
{
  engine.saveTo( new FileOutputStream( "temp/test/CustomPriceFormula.jar" ) );
}

Loading it back is just as easy:

private Engine load() throws Exception
{
  return FormulaRuntime.loadEngine( new FileInputStream( "temp/test/CustomPriceFormula.jar" ) );
}

Again, add the following to the main method to make it runnable:

app.save( engine );

QuickStart app2 = new QuickStart();
Engine engine2 = app2.load();
PriceFinderFactory factory2 = app2.factoryFor( engine2 );
BigDecimal price2 = app2.compute( factory2 );
System.out.println( "The result is " + price2 );

Alright. Run it.

Summary

As promised, you just…

  • created a spreadsheet defining a customized line item price computation,
  • made AFC compile it to Java classes,
  • used those classes in your application,
  • looked at the generated code in Java source form, and
  • saved and reloaded the classes from a .jar file.

Hopefully, you also played around with the spreadsheet, compiling different formulas. You really should.

Not bad. Now learn more about the goals, the design, the API, and the supported functions of AFC.

Posted by 1010
01.JAVA/Java2012. 9. 20. 07:02
반응형

출처: http://realcool.egloos.com/3924002

 

엑셀의 함수를 자바로 구현할 일이 있어서 찾아본 결과

http://www.formulacompiler.org/doc/reference/index.htm

위의 사이트를 어렵게 찾았습니다.

위의 사이트에서 라이브러리 다운받으시고

필요한 엑셀함수를 호출해서 사용하면 됩니다.

하나만 예로 들어 만들어보면 다음과 같습니다.

엑셀의 chiinv를 예로 들면 다음과 같습니다.

import org.formulacompiler.runtime.internal.RuntimeDouble_v2;

/**
* 카이제곱분포
* @author realcool@empal.com
*
*/
public class Chiinv {
/**
* 카이제곱분포
* @param a
* @param b
* @return
*/
public double chiinv(double _x,double _degFreedom){
return RuntimeDouble_v2.fun_CHIINV(_x, _degFreedom);
}
final double NORMDIST(double input1,double input2,double input3,double input4) {
double d;
if (input3 <= 0.0) {
Runtime_v2.fun_ERROR("#NUM! because sigma <= 0 in NORMDIST");
d = (double) -1;
} else
d = (input4 != 0.0
? (Math.abs((input1 - input2) / input3
* 0.7071067811865476) < 0.7071067811865476
? (0.5
+ 0.5 * RuntimeDouble_v2.fun_ERF((input1 - input2)
/ input3
* 0.7071067811865476))
: (input1 - input2) / input3 * 0.7071067811865476 > 0.0
? 1.0 - 0.5 * (RuntimeDouble_v2.fun_ERFC
(Math.abs((input1 - input2) / input3
* 0.7071067811865476)))
: 0.5 * (RuntimeDouble_v2.fun_ERFC
(Math.abs((input1 - input2) / input3
* 0.7071067811865476))))
: (Math.exp((input1 - input2) * (input1 - input2)
/ (-2.0 * input3 * input3))
/ (2.5066282746310002 * input3)));
return d;
}
public static void main(String[] args){
Chiinv c = new Chiinv();
double d = c.chiinv(0.05, 2);
System.out.println(d);
}
}

Since AFC only supports Microsoft Excel spreadsheet semantics at the moment, this reference uses Excel as a baseline for expected behaviour of the supported functions.

Cells, Values, Names
Strings, numbers, dates, booleans; blank cells; cell names; ranges; numeric precision
Numeric Operators
%, *, +, -, /, <, <=, <>, =, >, >=, ^
Numeric Functions
ABS, ACOS, ACOSH, ASIN, ASINH, ATAN, ATAN2, ATANH, CEILING, COMBIN, COS, COSH, DEGREES, EVEN, EXP, FACT, FLOOR, GEOMEAN, HARMEAN, INT, LN, LOG, LOG10, MOD, ODD, PERMUT, PI, POWER, RADIANS, RAND, ROUND, ROUNDDOWN, ROUNDUP, SIGN, SIN, SINH, SQRT, TAN, TANH, TRUNC
Financial Functions
DB, DDB, FV, IRR, MIRR, NPER, NPV, PMT, PV, RATE, SLN, SYD, VDB
Statistical Functions
AVEDEV, BETADIST, BETAINV, BINOMDIST, CHIDIST, CHIINV, CHITEST, CONFIDENCE, CORREL, CRITBINOM, DEVSQ, EXPONDIST, FDIST, FINV, FISHER, FISHERINV, FORECAST, FTEST, GAMMADIST, GAMMAINV, GAMMALN, HYPGEOMDIST, INTERCEPT, KURT, LARGE, LOGINV, LOGNORMDIST, MEDIAN, MODE, NEGBINOMDIST, NORMDIST, NORMINV, NORMSDIST, NORMSINV, PEARSON, PERCENTILE, PERCENTRANK, POISSON, PROB, QUARTILE, RANK, RSQ, SKEW, SLOPE, SMALL, STANDARDIZE, STDEV, STDEVP, STDEVPA, STEYX, SUMX2MY2, SUMX2PY2, SUMXMY2, TDIST, TINV, TRIMMEAN, TTEST, VAR, VARA, VARP, WEIBULL, ZTEST
String Support
&, <, <=, <>, =, >, >=, CLEAN, CONCATENATE, EXACT, FIND, LEFT, LEN, LOWER, MATCH, MID, PROPER, REPLACE, REPT, RIGHT, SEARCH, SUBSTITUTE, TRIM, UPPER
Boolean Functions And IF
AND, IF, NOT, OR, true
Date Functions
DATE, DAY, DAYS360, HOUR, MINUTE, MONTH, NOW, SECOND, TIME, TODAY, WEEKDAY, YEAR
Conversion Functions
CHAR, CODE, DATEVALUE, DOLLAR, FIXED, N, ROMAN, T, TEXT, TIMEVALUE, VALUE
Type Functions
ISNONTEXT, ISNUMBER, ISTEXT
Aggregators
AVEDEV, AVERAGE, COUNT, COUNTA, COVAR, DEVSQ, KURT, MAX, MIN, PRODUCT, SKEW, STDEV, STDEVP, SUM, SUMIF, SUMSQ, VAR, VARP
Database Table Aggregators
COUNTIF, DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, SUMIF
Lookup Functions
CHOOSE, HLOOKUP, INDEX, LOOKUP, MATCH, VLOOKUP
Limitations
Things that are known to not work quite as expected yet.

Note On The Sample Expressions

To ensure its correctness, all the example expressions and their results have been cited from automated tests that are run with every release build.

이 글과 관련있는 글을 자동검색한 결과입니다 [?]

by 수평선 | 2009/01/18 19:54 | 자바코드 | 트랙백 | 덧글(2)

트랙백 주소 : http://realcool.egloos.com/tb/3924002
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Commented by 노태광 at 2009/03/11 11:07
정말 좋은 자료를 찾았어요. 너무 감사드립니다.
한가지 여쭤보고 싶은게 있는데요.
NORMDIST 함수를 사용하고 싶은데. 라이브러리에 포함되어 있지 않은 것 같아서요.
제가 잘 몰라서 못찾는 것 같은데. 좀 알려주시면 고맙겠습니다.^^*
Commented by 수평선 at 2009/03/23 10:26
찾으시는 자료가 혹시 다음일거라 생각되네요..
package JSci.maths.statistics;

import JSci.maths.*;

/**
* The NormalDistribution class provides an object for encapsulating normal distributions.
* @version 1.1
* @author Jaco van Kooten
*/
public final class NormalDistribution extends ProbabilityDistribution implements NumericalConstants {
private double mean,variance;
private double pdfDenominator,cdfDenominator;

/**
* Constructs the standard normal distribution (zero mean and unity variance).
*/
public NormalDistribution() {
this(0.0,1.0);
}
/**
* Constructs a normal distribution.
* @param mu the mean.
* @param var the variance.
*/
public NormalDistribution(double mu,double var) {
mean=mu;
if(var<=0.0)
throw new OutOfRangeException("The variance should be (strictly) positive.");
variance=var;
pdfDenominator=SQRT2PI*Math.sqrt(variance);
cdfDenominator=SQRT2*Math.sqrt(variance);
}
/**
* Constructs a normal distribution from a data set.
* @param array a sample.
* @author Mark Hale
*/
public NormalDistribution(double array[]) {
double sumX=array[0];
double sumX2=array[0]*array[0];
for(int i=1;i<array.length;i++) {
sumX+=array[i];
sumX2+=array[i]*array[i];
}
mean=sumX/array.length;
variance=(sumX2 - array.length*mean*mean)/(array.length-1);
pdfDenominator=SQRT2PI*Math.sqrt(variance);
cdfDenominator=SQRT2*Math.sqrt(variance);
}
/**
* Returns the mean.
*/
public double getMean() {
return mean;
}
/**
* Returns the variance.
*/
public double getVariance() {
return variance;
}
/**
* Probability density function of a normal (Gaussian) distribution.
* @return the probability that a stochastic variable x has the value X, i.e. P(x=X).
*/
public double probability(double X) {
return Math.exp(-(X-mean)*(X-mean)/(2*variance))/pdfDenominator;
}
/**
* Cumulative normal distribution function.
* @return the probability that a stochastic variable x is less then X, i.e. P(x&lt;X).
*/
public double cumulative(double X) {
return SpecialMath.complementaryError(-(X-mean)/cdfDenominator)/2;
}
/**
* Inverse of the cumulative normal distribution function.
* @return the value X for which P(x&lt;X).
*/
public double inverse(double probability) {
checkRange(probability);
if(probability==0.0)
return -Double.MAX_VALUE;
if(probability==1.0)
return Double.MAX_VALUE;
if(probability==0.5)
return mean;
// To ensure numerical stability we need to rescale the distribution
double meanSave=mean,varSave=variance;
double pdfDSave=pdfDenominator,cdfDSave=cdfDenominator;
mean=0.0;
variance=1.0;
pdfDenominator=Math.sqrt(TWO_PI);
cdfDenominator=SQRT2;
double X=findRoot(probability, 0.0, -100.0, 100.0);
// Scale back
mean=meanSave;
variance=varSave;
pdfDenominator=pdfDSave;
cdfDenominator=cdfDSave;
return X*Math.sqrt(variance)+mean;
}
}

http://jsci.sourceforge.net/api/JSci/maths/statistics/NormalDistribution.html
위 주소입니다.
http://jsci.sourceforge.net/

소스다운로드 해서 분석하면 될것 같네요..
Posted by 1010
02.Oracle/DataBase2012. 9. 20. 04:09
반응형


--1. Buffer Cache Hit Ratio

SELECT ROUND(((1-(SUM(DECODE(name, 'physical reads', value,0))/

(SUM(DECODE(name, 'db block gets', value,0))+

(SUM(DECODE(name, 'consistent gets', value, 0))))))*100),2) || '%' "Buffer Cache Hit Ratio"

FROM V$SYSSTAT;

--2. Library Cache Hit Ratio

SELECT (1-SUM (reloads)/SUM(pins))*100 "Library Cache Hit Ratio"

From V$LIBRARYCACHE;

--3. Data Dictionary Cache Hit Ratio

SELECT (1-SUM(getmisses)/SUM(gets))*100 "Data Dictionary Hit Ratio"

FROM V$ROWCACHE;

-- 테이블 스페이스 사용량

SELECT a.tablespace_name,

a.total "Total(Mb)",

a.total - b.free "Used(Mb)",

nvl(b.free,0) "Free(Mb)",

round((a.total - nvl(b.free,0))*100/total,0) "Used(%)"

from ( select tablespace_name,

round((sum(bytes)/1024/1024),0) as total

from dba_data_files

group by tablespace_name) a,

( select tablespace_name,

round((sum(bytes)/1024/1024),0) as free

from dba_free_space

group by tablespace_name) b

where a.tablespace_name = b.tablespace_name(+)

order by a.tablespace_name;

--오라클서버의 메모리

select * from v$sgastat

select pool, sum(bytes) "SIZE"

from v$sgastat

where pool = 'shared pool'

group by pool

--cpu를 많이 사용하는 쿼리문과 프로세스아이디,시리얼번호,머신 알아내기

select c.sql_text

,b.SID

, b.SERIAL#

,b.machine

,b.OSUSER

,b.logon_time --이 쿼리를 호출한 시간

from v$process a, v$session b, v$sqltext c

where a.addr = b.paddr

and b.sql_hash_value = c.hash_value

--and a.spid = '675958'

order by c.PIECE

--cpu를 많이 사용하는 쿼리문과 프로세스아이디,시리얼번호,머신 알아내기

select c.sql_text

from v$process a, v$session b, v$sqltext c

where a.addr = b.paddr

and b.sql_hash_value = c.hash_value

and a.spid = '171'

order by c.PIECE

--프로세스 아이디를 이용하여 쿼리문 알아내기

select c.sql_text

,b.SID

, b.SERIAL#

,b.machine

,b.OSUSER

,b.logon_time --이 쿼리를 호출한 시간

from v$process a, v$session b, v$sqltext c

where a.addr = b.paddr

and b.sql_hash_value = c.hash_value

and a.spid = '1708032' --1912870/

order by c.PIECE

--세션 죽이기(SID,SERAIL#)

--ALTER SYSTEM KILL SESSION '8,4093'

--오라클 세션과 관련된 테이블*/

--select count(*) from v$session where machine ='머신이름' and schemaname ='스키마이름'

--현재 커서 수 확인

SELECT sid, count(sid) cursor

FROM V$OPEN_CURSOR

WHERE user_name = 'ilips'

GROUP BY sid

ORDER BY cursor DESC

SELECT sql_text, count(sid) cnt

FROM v$OPEN_CURSOR

GROUP BY sql_text

ORDER BY cnt DESC

select * from v$session_wait

select sid, serial#, username, taddr, used_ublk, used_urec

from v$transaction t, v$session s

where t.addr = s.taddr;

select * from sys.v_$open_cursor

--V$LOCK 을 사용한 잠금 경합 모니터링

SELECT s.username, s.sid, s.serial#, s.logon_time,

DECODE(l.type, 'TM', 'TABLE LOCK',

'TX', 'ROW LOCK',

NULL) "LOCK LEVEL",

o.owner, o.object_name, o.object_type

FROM v$session s, v$lock l, dba_objects o

WHERE s.sid = l.sid

AND o.object_id = l.id1

AND s.username IS NOT NULL

--락이 걸린 세션 자세히 알아보기

select a.sid, a.serial#,a.username,a.process,b.object_name,

decode(c.lmode,2,'RS',3,'RX',4,'S',5,'SRX',8,'X','NO') "TABLE LOCK",

decode (a.command,2,'INSERT',3,'SELECT',6,'UPDATE',7,'DELETE',12,'DROP TABLE',26,'LOCK TABLE','UNknown') "SQL",

decode(a.lockwait, NULL,'NO wait','Wait') "STATUS"

from v$session a,dba_objects b, v$lock c

where a.sid=c.sid and b.object_id=c.id1

and c.type='TM'

--락이 걸린 세션 간단히 알아보기

select a.sid, a.serial#, b.type, c.object_name, a.program, a.lockwait,

a.logon_time, a.process, a.osuser, a.terminal

from v$session a, v$lock b, dba_objects c

where a.sid = b.sid

and b.id1 = c.object_id

and b.type = 'TM';

select a.sid, a.serial#, a.username, a.process, b.object_name

from v$session a , dba_objects b, v$lock c

where a.sid=c.sid and b.object_id = c.id1

and c.type = 'TM'

--락이 걸린 세션을 찾아 내어 세션을 죽이려고 해도 죽지 않는 경우

--아래 쿼리문으로 OS단의 PROCESS ID를 찾아내어 OS에서 죽인다

--kill -9 프로세스아이디

select substr(s.username,1,11) "ORACLE USER", p.pid "PROCESS ID",

s.sid "SESSION ID", s.serial#, osuser "OS USER",

p.spid "PROC SPID",s.process "SESS SPID", s.lockwait "LOCK WAIT"

from v$process p, v$session s, v$access a

where a.sid=s.sid and

p.addr=s.paddr and

s.username != 'SYS'

--위 쿼리문의 결과가 있다면 락이 걸린 세션이 있다는것이므로 아래의 쿼리문으로 세션을 죽인다

ALTER SYSTEM KILL SESSION '11,39061'

alter session으로 죽지않는 프로세스 죽이기

1.oracle이 설치된 서버에 텔넷으로 root로 접속한다

2.su -오라클계정

3.sqlplus '/as sysdba''

4.connect system/sys

5.ALTER SYSTEM KILL SESSION '137,1723'

출처 : 파란 블로그 DINO 님.

Posted by 1010
02.Oracle/DataBase2012. 9. 18. 05:21
반응형
instr(object_name,'abcd')>0

where 절 밑에 object_name like '%abcd%' 로 검색하는 것보다

instr(object_name,'abcd') > 0 로 검색하면 더 빠르다..

 

 

 

Full Text Indexing using Oracle Text

Oracle Text, previously know as interMedia Text and ConText, is an extensive full text indexing technology allowing you to efficiently query free text and produce document classification applications. In this article I'll only scratch the surface of this very complex feature.

The examples in this article require access to the CTX_DDL package, which is granted as follows.

GRANT EXECUTE ON CTX_DDL TO <username>;

CONTEXT Indexes

The CONTEXT index type is used to index large amounts of text such as Word, PDF, XML, HTML or plain text documents. In this example we will store the data in a BLOB column, which allows us to store binary documents like Word and PDF as well as plain text. Using a CLOB is preferable if only plain text documents are being used.

First we build a sample schema to hold our data.

DROP TABLE my_docs;
DROP SEQUENCE my_docs_seq;
DROP PROCEDURE load_file_to_my_docs;

CREATE TABLE my_docs (
  id    NUMBER(10)     NOT NULL,
  name  VARCHAR2(200)  NOT NULL,
  doc   BLOB           NOT NULL
);

ALTER TABLE my_docs ADD (
  CONSTRAINT my_docs_pk PRIMARY KEY (id)
);

CREATE SEQUENCE my_docs_seq;

CREATE OR REPLACE DIRECTORY documents AS 'C:\work';

Next we load several files as follows.

CREATE OR REPLACE PROCEDURE load_file_to_my_docs (p_file_name  IN  my_docs.name%TYPE) AS
  v_bfile      BFILE;
  v_blob       BLOB;
BEGIN
  INSERT INTO my_docs (id, name, doc)
  VALUES (my_docs_seq.NEXTVAL, p_file_name, empty_blob())
  RETURN doc INTO v_blob;

  v_bfile := BFILENAME('DOCUMENTS', p_file_name);
  Dbms_Lob.Fileopen(v_bfile, Dbms_Lob.File_Readonly);
  Dbms_Lob.Loadfromfile(v_blob, v_bfile, Dbms_Lob.Getlength(v_bfile));
  Dbms_Lob.Fileclose(v_bfile);

  COMMIT;
END;
/

EXEC load_file_to_my_docs('FullTextIndexingUsingOracleText9i.doc');
EXEC load_file_to_my_docs('FullTextIndexingUsingOracleText9i.asp');
EXEC load_file_to_my_docs('XMLOverHTTP9i.asp');
EXEC load_file_to_my_docs('UNIXForDBAs.asp');
EXEC load_file_to_my_docs('emp_ws_access.sql');
EXEC load_file_to_my_docs('emp_ws_test.html');
EXEC load_file_to_my_docs('9ivsSS2000forPerformanceV22.pdf');

Next we create a CONTEXT type index on the doc column and gather table statistics.

CREATE INDEX my_docs_doc_idx ON my_docs(doc) INDEXTYPE IS CTXSYS.CONTEXT;

EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'MY_DOCS', cascade=>TRUE);

Finally we query table looking for documents with specific content.

SELECT SCORE(1) score, id, name
FROM   my_docs
WHERE  CONTAINS(doc, 'SQL Server', 1) > 0
ORDER BY SCORE(1) DESC;

     SCORE         ID NAME
---------- ---------- ------------------------------------------------
       100        127 9ivsSS2000forPerformanceV22.pdf

1 row selected.

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=2 Bytes=58)
   1    0   SORT (ORDER BY) (Cost=4 Card=2 Bytes=58)
   2    1     TABLE ACCESS (BY INDEX ROWID) OF 'MY_DOCS' (Cost=2 Card=2 Bytes=58)
   3    2       DOMAIN INDEX OF 'MY_DOCS_DOC_IDX' (Cost=0)


SELECT SCORE(1) score, id, name
FROM   my_docs
WHERE  CONTAINS(doc, 'XML', 1) > 0
ORDER BY SCORE(1) DESC;

     SCORE         ID NAME
---------- ---------- ------------------------------------------------
        74        123 XMLOverHTTP9i.asp
         9        125 emp_ws_access.sql

2 rows selected.

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=2 Bytes=58)
   1    0   SORT (ORDER BY) (Cost=4 Card=2 Bytes=58)
   2    1     TABLE ACCESS (BY INDEX ROWID) OF 'MY_DOCS' (Cost=2 Card=2 Bytes=58)
   3    2       DOMAIN INDEX OF 'MY_DOCS_DOC_IDX' (Cost=0)

CTXCAT Indexes

The CTXCAT index type is best suited to smaller text fragments that must be indexed along with other relational data. In this example the data will be stored in a VARCHAR2 column.

First we create a schema to hold the data.

DROP TABLE my_items;
DROP SEQUENCE my_items_seq;
EXEC CTX_DDL.DROP_INDEX_SET('my_items_iset');

CREATE TABLE my_items (
  id           NUMBER(10)      NOT NULL,
  name         VARCHAR2(200)   NOT NULL,
  description  VARCHAR2(4000)  NOT NULL,
  price        NUMBER(7,2)     NOT NULL
);

ALTER TABLE my_items ADD (
  CONSTRAINT my_items_pk PRIMARY KEY (id)
);

CREATE SEQUENCE my_items_seq;

Next we populate the schema with some dummy data.

BEGIN
  FOR i IN 1 .. 1000 LOOP
    INSERT INTO my_items (id, name, description, price)
    VALUES (my_items_seq.NEXTVAL, 'Bike: '||i, 'Bike Description ('||i||')', i);
  END LOOP;

  FOR i IN 1 .. 1000 LOOP
    INSERT INTO my_items (id, name, description, price)
    VALUES (my_items_seq.NEXTVAL, 'Car: '||i, 'Car Description ('||i||')', i);
  END LOOP;

  FOR i IN 1 .. 1000 LOOP
    INSERT INTO my_items (id, name, description, price)
    VALUES (my_items_seq.NEXTVAL, 'House: '||i, 'House Description ('||i||')', i);
  END LOOP;

  COMMIT;
END;
/

Next we create a CTXCAT index on the DESCRIPTION and PRICE columns and gather table statistics. In order to create the index we must create an index-set with a sub-index for each column referenced by the CATSEARCH function.

EXEC CTX_DDL.CREATE_INDEX_SET('my_items_iset');
EXEC CTX_DDL.ADD_INDEX('my_items_iset','price');

CREATE INDEX my_items_name_idx ON my_items(description) INDEXTYPE IS CTXSYS.CTXCAT
PARAMETERS ('index set my_items_iset');

EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'MY_ITEMS', cascade=>TRUE);

Finally we query table looking for items with a description that contains our specified words and an appropriate price.

SELECT id, price, name
FROM   my_items
WHERE  CATSEARCH(description, 'Bike', 'price BETWEEN 1 AND 5')> 0;

        ID      PRICE NAME
---------- ---------- ------------------------------------------------
         1          1 Bike: 1
         2          2 Bike: 2
         3          3 Bike: 3
         4          4 Bike: 4
         5          5 Bike: 5

5 rows selected.

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=150 Bytes=6000)
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'MY_ITEMS' (Cost=2 Card=150 Bytes=6000)
   2    1     DOMAIN INDEX OF 'MY_ITEMS_NAME_IDX'


SELECT id, price, name
FROM   my_items
WHERE  CATSEARCH(description, 'Car', 'price BETWEEN 101 AND 105 ORDER BY price DESC')> 0;

        ID      PRICE NAME
---------- ---------- ------------------------------------------------
      1105        105 Car: 105
      1104        104 Car: 104
      1103        103 Car: 103
      1102        102 Car: 102
      1101        101 Car: 101

5 rows selected.

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=150 Bytes=6000)
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'MY_ITEMS' (Cost=2 Card=150 Bytes=6000)
   2    1     DOMAIN INDEX OF 'MY_ITEMS_NAME_IDX'

Every column used to restrict the selection or order the output in the CATSEARCH function should have a sub-index within the index-set. The CTXCAT index type is transactional so there is no need to synchronize the index.

CTXRULE Indexes

The CTXRULE index type can be used to build document classification applications.

First we must define our document categories and store them, along with a suitable query for the MATCHES function.

DROP TABLE my_doc_categories;
DROP TABLE my_categories;
DROP SEQUENCE my_categories_seq;
DROP TABLE my_docs;
DROP SEQUENCE my_docs_seq;

CREATE TABLE my_categories (
  id        NUMBER(10)      NOT NULL,
  category  VARCHAR2(30)    NOT NULL,
  query     VARCHAR2(2000)  NOT NULL
);

ALTER TABLE my_categories ADD (
  CONSTRAINT my_categories_pk PRIMARY KEY (id)
);

CREATE SEQUENCE my_categories_seq;

INSERT INTO my_categories VALUES(my_categories_seq.NEXTVAL, 'Oracle', 'ABOUT(Oracle)');
INSERT INTO my_categories VALUES(my_categories_seq.NEXTVAL, 'SQL Server', 'ABOUT(SQL Server)');
INSERT INTO my_categories VALUES(my_categories_seq.NEXTVAL, 'UNIX', 'ABOUT(UNIX)');

Next we create a table to hold our documents.

CREATE TABLE my_docs (
  id    NUMBER(10)     NOT NULL,
  name  VARCHAR2(200)  NOT NULL,
  doc   CLOB           NOT NULL
);

ALTER TABLE my_docs ADD (
  CONSTRAINT my_docs_pk PRIMARY KEY (id)
);

CREATE SEQUENCE my_docs_seq;

Then we create an intersection table to resolve the many-to-many relationship between documents and categories.

CREATE TABLE my_doc_categories (
  my_doc_id       NUMBER(10)  NOT NULL,
  my_category_id  NUMBER(10)  NOT NULL
);

ALTER TABLE my_doc_categories ADD (
  CONSTRAINT my_doc_categories_pk PRIMARY KEY (my_doc_id, my_category_id)
);

Next we create a BEFORE INSERT trigger on the MY_DOCS table to automatically assign the documents to the relevant categories as they are being inserted. The MATCHES function is used to decide if the document matches any of our gategory queries. The resulting cursor is used to insert the matches into the intersect table.

CREATE OR REPLACE TRIGGER my_docs_trg
  BEFORE INSERT ON my_docs
  FOR EACH ROW
BEGIN
  FOR c1 IN (SELECT id
             FROM   my_categories
             WHERE  MATCHES(query, :new.doc)>0)
  LOOP
    BEGIN
      INSERT INTO my_doc_categories(my_doc_id, my_category_id)
      VALUES (:new.id, c1.id);
    EXCEPTION
      WHEN OTHERS THEN
        NULL;
    END;
  END LOOP;
END;
/

Next we create the CTXRULE index to support the trigger. For completeness we also create a CONTEXT index on the document itself, although this is not involved in the category assignment process.

CREATE INDEX my_categories_query_idx ON my_categories(query) INDEXTYPE IS CTXSYS.CTXRULE;
CREATE INDEX my_docs_doc_idx ON my_docs(doc) INDEXTYPE IS CTXSYS.CONTEXT;

EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'MY_CATEGORIES', cascade=>TRUE);
EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'MY_DOCS', cascade=>TRUE);
EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'MY_DOC_CATEGORIES', cascade=>TRUE);

Finally we test the mechanism by inserting some rows and checking the classification.

INSERT INTO my_docs (id, name, doc)
VALUES (my_docs_seq.NEXTVAL, 'Oracle Document', 'This document constains the word Oracle!');

INSERT INTO my_docs (id, name, doc)
VALUES (my_docs_seq.NEXTVAL, 'SQL Server Document', 'This document constains the words SQL Server!');

INSERT INTO my_docs (id, name, doc)
VALUES (my_docs_seq.NEXTVAL, 'UNIX Document', 'This document constains the word UNIX!');

INSERT INTO my_docs (id, name, doc)
VALUES (my_docs_seq.NEXTVAL, 'Oracle UNIX Document', 'This document constains the word UNIX and the word Oracle!');


COLUMN name FORMAT A30;
SELECT a.name, b.category
FROM   my_docs a,
       my_categories b,
       my_doc_categories c
WHERE  c.my_doc_id      = a.id
AND    c.my_category_id = b.id;

NAME                           CATEGORY
------------------------------ ------------------------------
Oracle Document                Oracle
SQL Server Document            SQL Server
UNIX Document                  UNIX
Oracle UNIX Document           UNIX
Oracle UNIX Document           Oracle

5 rows selected.

The output shows that the documents have been assigned to the correct categories. Note, the "Oracle UNIX Document" document has been assigned to both the "Oracle" and "UNIX" categories.

Index Maintenance

Not all Oracle Text indexes are automatically updated as records are added or deleted. To synchronize the index with the table you must call.

SQL> EXEC CTX_DDL.SYNC_INDEX('my_docs_doc_idx');

Regular synchronizations of the index can be automated using the DBMS_JOB package. The following script is provided to make this task easier.

$ORACLE_HOME/ctx/sample/script/drjobdml.sql

It can be called from SQL*Plus whilst logged on as the index owner as follows.

SQL> @drjobdml.sql index-name interval-mins
SQL> @drjobdml.sql my_docs_doc_idx 60

Regular synchronization of text indexes can cause fragmentation which affects query performance. To correct this situation the index can be rebuilt or optimized. Index optimization can be performed in three basic modes (FAST, FULL or TOKEN). The FAST mode compacts fragmented rows but does not remove old data.

BEGIN
  CTX_DDL.OPTIMIZE_INDEX('my_docs_doc_idx','FAST');
END;
/

The FULL mode optimizes either the entire index or a portion of it, with old data removed.

BEGIN
  CTX_DDL.OPTIMIZE_INDEX('my_docs_doc_idx','FULL');
END;
/

The TOKEN mode perfoms a full optimization for a specific token.

BEGIN
  CTX_DDL.OPTIMIZE_INDEX('my_docs_doc_idx','TOKEN', token=>'Oracle');
END;
/

For more information see:

Hope this helps. Regards Tim...

Back to the Top.

Posted by 1010