Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 19 Current »

ICE 내부 특정 NodeType에 대한 쿼리를 실행하기 위한 API 유형으로, 다음과 같은 추가적인 항목을 정의한다.

pid

valueType

description

tid

REFERENCE

대상 Node Type

customFilter

STRING

프로그래밍으로 검색 질의를 작성하고 싶은 경우 해당 필터 클래스 설정

query

CHILDREN

ICE내에서 공통으로 사용하는 Lucene 기반의 쿼리를 이용하여 검색 조건을 정의

(apiQuery 에 상세 정의)

apiQuery

pid

valueType

description

methohd

CODE

조회형식, 검색조건

  • "method": "matching"

  • "method": "sorting"

  • "method": "page"

(아래 method 상세 정의)

field

STRING

검색할 대상 nodeType의 propertyType id (pid)

value

STRING

조건값

useCacheKey

BOOLEAN

cacheKey 조합에 사용 여부

useCacheKey

cacheKey조합에 사용 여부를 apiQuery field 단위로 설정할 수 있다.

apiConfig의 "cacheable": true, cacheTime 설정이 되어있어야 useCacheKey 사용 가능하다.

default : true

 "useCacheKey": true
{
  "typeId": "api",
  "category": "snack",
  "apiId": "list",
  "apiName": "snack List",
  "apiType": "service",
  "method": "GET",
  "parameters": [
  ],
  "statistic": true,
  "aggregation": false,
  "root": {
    "configId": "root",
    "tid": "snack",
    "type": "query",
    "cacheable": true,
    "cacheTime": 60,
    "customResponse": "sampleResponse",
    "query": [
      {
        "method": "matchingShould",
        "field": "id",
        "value": "{{:id}}"
      },
      {
        "method": "matchingShould",
        "field": "name",
        "value": "{{:name}}"
      }
    ],
    "response": [
      {
        "field": "_all_",
        "type": "all"
      }
    ]
  }

{{protocol}}://{{hostname}}:{{port}}/svc/snack/list?_siteId=bestshop&id=104&name=오레오

cacheKey api::snack>list?&id.matchingShould=104&name.matchingShould=오레오

{
    "result": "200",
    "resultMessage": "SUCCESS",
    "totalCount": 2,
    "totalTypeCount": 20,
    "resultCount": 2,
    "items": [
        {
            "id": "104",
            "label": "쿠크다스",
            "name": "쿠크다스",
            "idx": 1
        },
        {
            "id": "103",
            "label": "오레오",
            "name": "오레오",
            "idx": 2
        }
    ]
}

 "useCacheKey": false
{
  "typeId": "api",
  "category": "snack",
  "apiId": "list",
  "apiName": "snack List",
  "apiType": "service",
  "method": "GET",
  "parameters": [
  ],
  "statistic": true,
  "aggregation": false,
  "root": {
    "configId": "root",
    "tid": "snack",
    "type": "query",
    "cacheable": true,
    "cacheTime": 60,
    "customResponse": "sampleResponse",
    "query": [
      {
        "method": "matchingShould",
        "field": "id",
        "value": "{{:id}}",
        "useCacheKey": false
      },
      {
        "method": "matchingShould",
        "field": "name",
        "value": "{{:name}}"
      }
    ],
    "response": [
      {
        "field": "_all_",
        "type": "all"
      }
    ]
  }
}

{{protocol}}://{{hostname}}:{{port}}/svc/snack/list?_siteId=bestshop&id=104&name=오레오{{protocol}}://{{hostname}}:{{port}}/svc/snack/list?_siteId=bestshop&id=105&name=오레오

cacheKey api::snack>list?&name.matchingShould=오레오

cacheKey에서 id 제외

[ id=104, name=오레오 ] 로 검색 후 cacheKey에 60초간 캐싱

이후 [ id=105, name=오레오 ] 로 검색하더라도 60초간 응답결과는 변화가 없다.

{
    "result": "200",
    "resultMessage": "SUCCESS",
    "totalCount": 2,
    "totalTypeCount": 20,
    "resultCount": 2,
    "items": [
        {
            "id": "104",
            "label": "쿠크다스",
            "name": "쿠크다스",
            "idx": 1
        },
        {
            "id": "103",
            "label": "오레오",
            "name": "오레오",
            "idx": 2
        }
    ]
}

method

PropertyType analyzer에 의한 색인(index)에 query Method로 질의를 할 수 있다.

 analyzer 정의 참조

루씬(Lucene)

  • 고성능 정보 검색(IR*, Information retrieval) 라이브러리

  • 색인과 검색의 기능을 담당

색인(index)

대량 문서에서 원하는 내용을 빠르게 검색하고자 할 때 원본 문서를 색인하고 검색하기 좋은 형태로 변환해 색인으로 만들어두는 처리 과정(indexing), 이 과정을 거친 결과물(index)

  1. 텍스트 추출(Parser)

  2. 텍스트 분석(Analysis)

  3. 색인(Index)

    • 해당 단어가 어느 문서에 들어있는지 등을 자료구조로 만든다

검색(searching)

색인에 들어있는 토큰을 기준으로 해당하는 토큰이 포함된 문서를 찾아내서 사용자 관점의 우선순위를 부여하는(ranking) 과정을 말함

Analyzer는 Tokenizer와 TokenFitler로 구성된다.

  • Tokenizer : Text를 Token으로 분리

  • TokenFilter : 분리된 Token을 정제

AnalyzerType

src/test/java/net/ion/ice/services/AnalyzerTest.java

simple

  • SimpleAnalyzer : lucene-analyzer-common에 존재하는 analyzer로 문자가 아닌것(기호/숫자)을 기준으로 나누고 소문자로 변경

    • LowerCaseTokenizer : 영문 분할용으로 대문자를 소문자로 바꿔서 분할하며, LetterTokenizer + LowerCaseFitler의 조합

    • @Override
      protected int normalize(int c) {
        return Character.toLowerCase(c);
      }
 Sample sentence : "My Friends Tigger & Pooh, 2007-2010. 내 친구 티거와 곰돌이 푸우"

my
friends
tigger
pooh

친구
티거와
곰돌이
푸우

  • simple은 예외로 tokenize된 word를 색인하지 않고 전체 문장을 통으로 인덱싱하고 있다.

    • 검색 시 tokenize된 단어로 matching으로 부분 검색을 할 수 없다.

    • 전체 문장이 매치되는 matching 검색 가능

    • wildcard로 like 검색 대체 가능

 Sample sentence : "My Friends Tigger Pooh, 2007-2010. 내 친구 티거와 곰돌이 푸우"

SEARCH SUCCESS {{protocol}}://{{hostname}}:{{port}}/node/testIndex?simple_matching=My Friends Tigger Pooh, 2007-2010. 내 친구 티거와 곰돌이 푸우

NO DATA {{protocol}}://{{hostname}}:{{port}}/node/testIndex?simple_matching=Pooh

NO DATA {{protocol}}://{{hostname}}:{{port}}/node/testIndex?simple_matching=pooh

SEARCH SUCCESS {{protocol}}://{{hostname}}:{{port}}/node/testIndex?simple_wildcard=Pooh

SEARCH SUCCESS {{protocol}}://{{hostname}}:{{port}}/node/testIndex?simple_wildcard=pooh

code

  • CodeAnalyzer

    • CodeTokenizer

    • @Override
      protected boolean isTokenChar(int c) {
          return ! (Character.isWhitespace(c) || c == ',') ;
      }
    • LowerCaseFilter : 소문자로 통일 

 Sample sentence : "My Friends Tigger & Pooh, 2007-2010. 내 친구 티거와 곰돌이 푸우"

my
friends
tigger
&
pooh
2007-2010.

친구
티거와
곰돌이
푸우

simpleCode

  • SimpleCodeAnalyzer

    • SimpleCodeTokenizer

    • @Override
      protected boolean isTokenChar(int c) {
          return ! (c == ',') ;
      }
    • LowerCaseFilter : 소문자로 통일 

 Sample sentence : "My Friends Tigger & Pooh, 2007-2010. 내 친구 티거와 곰돌이 푸우"

my friends tigger & pooh
2007-2010. 내 친구 티거와 곰돌이 푸우

whitespace

  • WhitespaceAnalyzer : lucene-analyzer-common에 존재하는 analyzer로 공백이나 탭등을 기준으로 tokenize를 수행

    • WhitespaceTokenizer : 공백 문자로 텍스트를 분할

    • @Override
      protected boolean isTokenChar(int c) {
        return !Character.isWhitespace(c);
      }
 Sample sentence : "My Friends Tigger & Pooh, 2007-2010. 내 친구 티거와 곰돌이 푸우"

My
Friends
Tigger
&
Pooh,
2007-2010.

친구
티거와
곰돌이
푸우

standard

  • StandardAnalyzer : lucene-core에 포함된 analyzer로 유니코드 텍스트 분할 알고리즘을 사용하여 텍스트를 단어 경계에서 단어로 나눈다. 대부분의 구두점제거, 소문자화, 불용어 제거.

    • StandardTokenizer

    • StandardTokenFilter

    • LowerCaseTokenFilter

    • StopTokenFilter

 Sample sentence : "My Friends Tigger & Pooh, 2007-2010. 내 친구 티거와 곰돌이 푸우"

my
friends
tigger
pooh
2007
2010

친구
티거와
곰돌이
푸우

cjk

  • CJK (중국어, 일본어 및 한국어)

  • NoStopCJKAnalyzer : StandardTokenizer로 텍스트를 토큰 화하고, CJKWidthFilter로 콘텐츠를 정규화하고, LowerCaseFilter로 대소 문자를 접고, CJKBigramFilter로 CJK의 bigrams를 형성.

    • StandardTokenizer

    • CJKWidthFilter

    • LowerCaseFilter

    • CJKBigramFilter

 Sample sentence : "My Friends Tigger & Pooh, 2007-2010. 내 친구 티거와 곰돌이 푸우"

my
friends
tigger
pooh
2007
2010

친구
티거
거와
곰돌
돌이
푸우

PropertyType의 default analyzer 기준

propertyType

value

default analyzer

idable

true

simpleCode

labelable

true

cjk

valueType

CODE

CODES

REFERENCES

PARTS

simpleCode

TEXT

standard

others

simple

analyzer에 따라 같은 Method 질의의 결과가 달라질 수 있다.

 Sample sentence : 동해물과 백두산이 마르고

analyzer simple

동해물과 백두산이 마르고

analyzer code

동해물과
백두산이
마르고

analyzer standard

동해물과
백두산이
마르고

analyzer cjk

동해
해물
물과
백두
두산
산이
마르
르고

SEARCH SUCCESS {{protocol}}://{{hostname}}:{{port}}/node/testIndex?simple_matching=동해물과 백두산이 마르고

NO DATA {{protocol}}://{{hostname}}:{{port}}/node/testIndex?simple_matching=동해물과

SEARCH SUCCESS {{protocol}}://{{hostname}}:{{port}}/node/testIndex?code_matching=동해물과

SEARCH SUCCESS {{protocol}}://{{hostname}}:{{port}}/node/testIndex?standard_matching=동해물과

SEARCH SUCCESS {{protocol}}://{{hostname}}:{{port}}/node/testIndex?cjk_matching=동해물과

NO DATA {{protocol}}://{{hostname}}:{{port}}/node/testIndex?simple_matching=해물

NO DATA {{protocol}}://{{hostname}}:{{port}}/node/testIndex?code_matching=해물

NO DATA {{protocol}}://{{hostname}}:{{port}}/node/testIndex?standard_matching=해물

SEARCH SUCCESS {{protocol}}://{{hostname}}:{{port}}/node/testIndex?cjk_matching=해물

SEARCH SUCCESS {{protocol}}://{{hostname}}:{{port}}/node/testIndex?cjk_matching=동해물과 백두

SEARCH SUCCESS {{protocol}}://{{hostname}}:{{port}}/node/testIndex?cjk_matching=산이 마르고

 Sample sentence : This is a sample index

analyzer simple

This is a sample index

analyzer code

this
is
a
sample
index

analyzer standard

sample
index

analyzer cjk

this
is
a
sample
index

analyzer id

This
is
a
sample
index

SEARCH SUCCESS {{protocol}}://{{hostname}}:{{port}}/node/testIndex?simple_matching=This is a sample index

NO DATA {{protocol}}://{{hostname}}:{{port}}/node/testIndex?simple_matching=This

SEARCH SUCCESS {{protocol}}://{{hostname}}:{{port}}/node/testIndex?code_matching=this

NO DATA {{protocol}}://{{hostname}}:{{port}}/node/testIndex?standard_matching=this

SEARCH SUCCESS {{protocol}}://{{hostname}}:{{port}}/node/testIndex?cjk_matching=this

ID

Description

matching

like

notMatching

not like

matchingShould

or 검색

should 끼리 or로 처리

wildcard

like

notWildcard

not like

wildcardShould

or 검색

should 끼리 or로 처리

equals

only DB

above

>=

below

<=

excess

>

under

<

fromto

{
  "field": "created",
  "method": "fromto",
  "value": "20200101~20201231"
}

hasReferenced

referenceJoin

PropertyType의 valueTypeREFERENCE 인 항목인 경우에 사용 가능

참조 nodeType (referenceType)에 Join 을 할 수 있다

{
  "field": "product",
  "method": "referenceJoin",
  "value": "saleSatatus_matching=selling&saleEndDate_above={{:today}}"
}

sorting

정렬

{
  "method": "sorting",
  "value": "created desc"
}

page

페이지 번호

default : 1

pageSize

페이징 기준 사이즈

default : 10


  • Param 으로 page, pageSize 가 들어오면 페이징 처리

  • Response 응답 결과에 페이징 관련 필드 함께 내려옴

    • totalCount : 검색된 결과 페이징 제외된 순수 카운트

    • totalTypeCount : noticeBoard nodeType의 데이터 노드리스트 카운트

    • resultCount : Response 결과 카운트

    • pageSize : 페이징 기준 사이즈

    • pageCount : 페이징 된 페이지 건수

    • currentPage : 현재 페이지 번호

{
    "result": "200",
    "resultMessage": "SUCCESS",
    "totalCount": 38,
    "totalTypeCount": 489,
    "resultCount": 10,
    "pageSize": 10,
    "pageCount": 4,
    "currentPage": 1,
    "items": [
        {
            "id": 1716647245,
            "title": "공지합니다. (수정)",
            "owner": {
                "value": "anonymous",
                "label": "Anonymous User",
                "refId": "user::anonymous"
            },
            "created": "2020-07-30 15:38:09"
        }
        ...
    ]
}

includeReferenced

PropertyType의 valueTypeREFERENCED 인 항목인 경우에 사용 가능

하위 노드 리스트를 pid 객체에 반환

  • users의 REFERENCED 리스트

    • value에 콤마 구분자로 N개 가능

{
  "method": "includeReferenced",
  "value": "users"
}
  • result :

{
    "result": "200",
    "resultMessage": "SUCCESS",
    "item": {
        "id": "admin",
        "typeId": "adminGroup",
        "name": "Admin Group",
        "users": [
            {
                "id": "admin1",
                "group": {
                    "value": "admin",
                    "label": "Admin Group",
                    "refId": "admin"
                },
                "name": "관리자테스트",
            },
            {
                "id": "defaultAdmin",
                "group": {
                    "value": "admin",
                    "label": "Admin Group",
                    "refId": "admin"
                },
                "name": "Default Admin User"
            }
        ]
    }
}

referenceView

PropertyType의 valueTypeREFERENCE 인 항목인 경우에 사용 가능

참조 객체 데이터를 읽어와서 Object로 pid 객체의 item에 리턴

{
  "method": "referenceView",
  "value": "seller"
}
  • 일반 쿼리 result :

{
    "result": "200",
    "resultMessage": "SUCCESS",
    "totalCount": 311,
    "totalTypeCount": 311,
    "resultCount": 1,
    "more": true,
    "moreCount": 311,
    "items": [
        {
            "id": 1762538,
            "label": "LG G pad 5 10.1 FHD WiFi",
            "seller": {
                "value": "1174839437",
                "label": "[seller] LG U+",
                "refId": "1174839437"
            }
        }
    ]
}
  • referenveView 포함 쿼리 result :

{
    "result": "200",
    "resultMessage": "SUCCESS",
    "totalCount": 311,
    "totalTypeCount": 311,
    "resultCount": 1,
    "more": true,
    "moreCount": 311,
    "items": [
        {
            "id": 1762538,
            "label": "LG G pad 5 10.1 FHD WiFi",
            "seller": {
                "value": "1174839437",
                "label": "[seller] LG U+",
                "refId": "1174839437",
                "item": {
                    "id": "1174839437",
                    "name": "[seller] LG U+",
                    "sellerType": {
                        "value": "individual",
                        "label": "개인"
                    },
                    "address": {
                        "id": "3366057",
                        "address": "서울 강남구",
                        "detailAddress": "테헤란로10길 15",
                        "zipCode": "06234",
                        "fullAddress": "(06234) 서울 강남구 테헤란로10길 15",
                        "label": ""
                    }
                    
                    ...
                    
                }
            }
        }
    ]
}

facet

value 기준 group by 된 count 를 Object로 반환

{
  "method": "facet",
  "value": "apiType,user"
}
{
    "result": "200",
    "resultMessage": "SUCCESS",
    "totalCount": 81,
    "totalTypeCount": 81,
    "resultCount": 81,
    "facets": {
        "apiType": {
            "internal": 5,
            "service": 12,
            "admin": 64
        },
        "user": {
            "customer::233174268": 11,
            "admin::system": 58
        }
    },
    "items": [
        {
            ...
        }
    ]
}

limit

쿼리 결과 제한 건수

{
  "method": "limit",
  "value": "2"
}

resultCount : 2

{
    "result": "200",
    "resultMessage": "SUCCESS",
    "totalCount": 311,
    "totalTypeCount": 311,
    "resultCount": 2,
    "more": true,
    "moreCount": 155,
    "items": [
        
        ...
        
    ]
}

customFilter

apiConfig의 query 조건으로 정의가 힘든 경우 직접 검색 질의를 커스텀 할 수 있다.

apiQuery에 customFilter가 AND로 질의가 추가된다.

커스텀 처리가 필요한 경우 해당 서비스 정의를 해야한다.

아래는 customFilter를 추가하는 사례이다.

  • Class 추가

    • location : net/ion/ice/core/query/filter

    • implements QueryFilter 하는 class 를 하나 생성한다.

  • @Component 어노테이션 추가

    • @Component("productSearchFilter")

  • custom 질의 작성

    • createQuery안에 Lucene에서 제공하는 쿼리로 직접 질의를 작성할 수 있다.

@Component("sampleFilter")
public class SampleFilter implements QueryFilter{
    @Override
    public Query createQuery(QueryContext context) {
        BooleanQuery.Builder searchQueryBuilder = new BooleanQuery.Builder();
        String tags = context.getDataStringValue("tags");

        if ("".equals(tags)) {
            return null;
        }
        BooleanQuery.Builder searchValueQueryBuilder = new BooleanQuery.Builder();
        try {
            Query tagsQuery = LuceneQueryUtils.createLuceneQuery(new QueryTerm(QueryTerm.QueryTermType.NODE, "tags", "code", "matching", tags, PropertyType.ValueType.STRING));
            searchValueQueryBuilder.add(tagsQuery, BooleanClause.Occur.SHOULD);
        } catch (IOException e) {
        }
        searchQueryBuilder.add(searchValueQueryBuilder.build(), BooleanClause.Occur.MUST);
        return searchQueryBuilder.build();
    }
}

  • apiConfig에 customFilter 세팅

    • @Component 어노테이션 명으로 작성한다.

  • 아래 API 설명

    • apiConfig query

      • name을 wildcard로 쿼리

    • customFilter

      • tags를 matching으로 쿼리

name의 "analyzer": "simple" - like 검색을 wildcard로 할 수 있다.

tags의 "analyzer": "code" - 콤마로 tokenize 되어있으므로 쪼개진 word에 대하여 matching으로 equals 검색을 할 수 있다.

 sample snack schema 정의 참조
[
  {
    "typeId": "nodeType",
    "tid": "snack",
    "parentId": "test",
    "repositoryType": "node",
    "typeName": "간식",
    "standaloneIndex": false,
    "microservice": "test",
    "propertyTypes": [
      {
        "pid": "id",
        "name": "ID",
        "valueType": "STRING",
        "idable": true,
        "indexable": true,
        "labelable": false,
        "required": true,
        "idType": "",
        "orderNo": 10
      },
      {
        "pid": "name",
        "name": "Name",
        "valueType": "STRING",
        "idable": false,
        "indexable": true,
        "analyzer": "simple",
        "labelable": true,
        "required": true,
        "orderNo": 20
      },
      {
        "pid": "vendor",
        "name": "vendor",
        "valueType": "STRING",
        "idable": false,
        "indexable": true,
        "analyzer": "code ",
        "labelable": true,
        "required": false,
        "orderNo": 30
      },
      {
        "pid": "tags",
        "name": "tags",
        "valueType": "STRING",
        "idable": false,
        "indexable": true,
        "analyzer": "code",
        "labelable": true,
        "required": false,
        "orderNo": 40
      }
    ]
  }
]

{
    "typeId": "api",
    "category": "snack",
    "apiId": "search",
    "apiName": "snack search List",
    "apiType": "service",
    "method": "GET",
    "parameters": [
      {
        "parameter": "name",
        "name": "이름",
        "valueType": "STRING",
        "required": false
      },
      {
        "parameter": "tags",
        "name": "검색어",
        "valueType": "STRING",
        "required": false
      }
    ],
    "statistic": true,
    "aggregation": false,
    "root": {
      "configId": "root",
      "tid": "snack",
      "type": "query",
      "customFilter": "sampleFilter",
      "query": [
        {
          "method": "wildcard",
          "field": "name",
          "value": "{{:name}}"
        }
      ],
      "response": [
        {
          "field": "id",
          "type": "field",
          "value": ""
        },
        {
          "field": "name",
          "type": "field",
          "value": ""
        },
        {
          "field": "vendor",
          "type": "field",
          "value": ""
        },
        {
          "field": "tags",
          "type": "field",
          "value": ""
        }
      ]
    }
  }
  • name like ‘%오레오%’인 검색 결과

{{protocol}}://{{hostname}}:{{port}}/svc/snack/search?_siteId=bestshop&name=오레오

{
    "result": "200",
    "resultMessage": "SUCCESS",
    "totalCount": 3,
    "totalTypeCount": 20,
    "resultCount": 3,
    "items": [
        {
            "id": "103",
            "name": "오레오",
            "vendor": "크래프트푸즈,동서식품",
            "tags": "초콜릿쿠키,하얀크림,샌드"
        },
        {
            "id": "119",
            "name": "오레오 민트초코",
            "vendor": "크래프트푸즈,동서식품",
            "tags": "민트초코,초코쿠키"
        },
        {
            "id": "120",
            "name": "오레오 딸기",
            "vendor": "크래프트푸즈,동서식품",
            "tags": "딸기"
        }
    ]
}
  • name like ‘%오레오%’ 이고 tags include ‘민트초코’ 인 검색 결과

{{protocol}}://{{hostname}}:{{port}}/svc/snack/search?_siteId=bestshop&name=오레오&tags=민트초코

{
    "result": "200",
    "resultMessage": "SUCCESS",
    "totalCount": 1,
    "totalTypeCount": 20,
    "resultCount": 1,
    "items": [
        {
            "id": "119",
            "name": "오레오 민트초코",
            "vendor": "크래프트푸즈,동서식품",
            "tags": "민트초코,초코쿠키"
        }
    ]
}

  • No labels