앞서서 Solr의 기술 제품 예제를 실행시켜봤다.

여기서는 Solr 예제 사이트에 있는 몇 가지 검색(Search - Query) 방법을 정리한다.

 

  1. 설치
  2. 기술제품과 검색식
  3. 스키마(Schema)
  4. DIH (Data Import Handler)

 

 

앞서 정리한 것과 같이, 다음 명령어로 Solr 예제 중 기술 제품을 실행한다.

         bin\solr start -e techproducts

 

첫 번째 검색은 한 단어 검색(Search for a Single Term)이다.

Solr 관리자 페이지에서 techproducts 코어를 선택하고, Query 메뉴를 선택해서 검색을 할 수 있도록 한다.

익숙해지면 웹 브라우저, curl, Postman 등에서 URL로 지정해서 검색하는 것이 편리하다.

 

다음 그림과 같이 Query 메뉴를 실행한 화면에서

q 입력상자에 electronics을 입력하고 실행 버튼(Execute Query)을 클릭해서 검색을 실행한다.

q의 기본 입력값은 *:*로,  콜론(:) 앞의 *는 모든 필드, 뒤의 *는 모든 값을 의미한다.

따라서 모든 필드에 대해서 특정한 값을 조회하면 *:electronics 으로 입력해야 할 것 같지만, electronics 만 사용한다.

 

위 그림에서 id, name, menu, cat 등의 필드 명이 출력되는 것을 볼 수 있다.

이번에는 전체 필드가 아닌, 이 필드 중 cat 필드에 있는 값을 검색한다.

특정한 필드의 특정한 값을 검색할 경우(Field Searches)에는 cat:electronics와 같이 필드명을 콜론으로 구분해서 사용한다.

      curl http://localhost:8983/solr/techproducts/select?q=cat:electronics

electronics으로 검색했을 때는 14건이 검색되었지만,

cat:electronics으로 cat필드에 대해서 검색했을 때는 12건이 검색된다.

 

여러 개의 단어로 검색 하는 구절 검색(Phrase Search)은 쌍따옴표("")를 이용한다.

먼저, SDRAM Unbuffered 로 검색하면, 4건이 검색된다.

      http://localhost:8983/solr/techproducts/select?q=SDRAM%20Unbuffered

 

그리고, "SDRAM Unbuffered"로 검색하면 3건이 검색된다.

      http://localhost:8983/solr/techproducts/select?q=%22SDRAM%20Unbuffered%22

 

쌍따옴표("" %22) 없이 검색하면

구절내의 단어를 분리해서 입력한 단어 2개 중 하나라도 있으면 출력한다.

일종의 OR 검색이 실행된 것이다.

쌍따옴표를 사용할 경우에는 해당한 구절이 있는 문서만 출력한다.

 

Solr 예제의 마지막은 결합 검색(Combining Searches)이다.

electronics music 로 검색하면

      http://localhost:8983/solr/techproducts/select?q=electronics%20music

32건의 문서가 검색된다.

앞서의 예제처럼 electronics이 있거나(OR) music 이 있는 문서가 검색 된 것이다.

 

+electronics +music으로 검색하면 1건이 검색된다.

      http://localhost:8983/solr/techproducts/select?q=%2Belectronics%20%2Bmusic

electronics과 music이 있는 문서만 검색 된 것이다.

즉, electronics가 있고(AND)  music이 있는 문서가 검색된 것으로 일종의 AND 검색이 된 것이다.

 

이번에는 electronics -music 로 검색하면 13건이 검색된다.

electronics가 있지만 music 이라는 단어가 없는(-) 문서만 검색된다.

 

이상의 내용은 Solr의 기본 예제에 있는 내용으로,

전체 필드를 대상으로 한 결합 검색식을 필드에 적용해서 응용할 수 있다.

 

cat:electronics cat:music 으로 검색하면, 12건의 결과가 검색된다.

cat 필드에 electronics가 있거나 music 이 있는 데이터가 조회되는 것이다.

cat:electronics cat:musiccat:electronics OR cat:music 으로 사용할 수 있다.

      http://localhost:8983/solr/techproducts/select?q=cat%3Aelectronics%20cat%3Amusic

      http://localhost:8983/solr/techproducts/select?q=cat%3Aelectronics%20OR%20cat%3Amusic

 

즉 앞서서 필드를 지정하지 않고, 전체 필드로 사용했던 검색식을 필드를 대상으로로도 사용할 수 있다.

 

+cat:electronics +cat:music 은 cat 필드에 electronics가 있고 music 이 있는 데이터로 1건이 검색된다.

+cat:electronics +cat:musiccat:electronics AND cat:music 로도 사용할 수 있다.

      http://localhost:8983/solr/techproducts/select?q=%2Bcat%3Aelectronics%20%2Bcat%3Amusic

      http://localhost:8983/solr/techproducts/select?q=cat%3Aelectronics%20AND%20cat%3Amusic

 

cat:electronics -cat:music 은 cat 필드에 electronics가 있지만 music 이 없는 데이터로 11건이 검색된다.

      http://localhost:8983/solr/techproducts/select?q=cat%3Aelectronics%20-cat%3Amusic

 

이 외에 DMBS의 LIKE 문처럼 cat:elect* 을 사용해서 cat필드의 내용 중 elect으로 시작하는 단어가 있는 문서 14건을 검색할 수 있다.

이 예제는 와일드카드(*)로 부분 문자열 검색을 나타내기도 하지만, 앞서 설명에서 빠진 중요한 개념을 가진 예제이다.

앞서의 첫 이미지를 자세히 보면

cat 필드는 문자열 값을 여러 개 가진 배열 타입인 것을 알 수 있다.

측, cat 필드는 ["electronics", "hard drive"]로 두 개의 문자열(“”)을 가진 배열[]이다.

다른 필드는 필드에 하나의 값을 가지지만 cat과 features는 여러 개의 값을 가진 배열이다.

(필드 타입에 배열이 있다는 점을 기억해야 한다.)

 

그리고, 이상에서 사용한 검색식들은 cat 필드의 값 중에서 검색하고 하는 문자와 일치하는 것만 조회 했다.

cat: electronics은 배열에 저장된 값이 정확하게 electronics일 때만 조회 된 것이다.

cat:elect*으로 조회할 경우에는 "electronics and computer1", "electronics and stuff2"가 있는 것도 조회 되었다.

cat: electronics은 일치하는 값만 조회하기 때문에 이 결과가 조회되지 않았다.

{
        "id":"3007WFP",
        "name":"Dell Widescreen UltraSharp 3007WFP",
        "manu":"Dell, Inc.",
        "manu_id_s":"dell",
        "cat":["electronics and computer1"],
        "features":["30\" TFT active matrix LCD, 2560 x 1600, .25mm dot pitch, 700:1 contrast"],
        "includes":"USB cable",
        "weight":401.6,
        "price":2199.0,
        "price_c":"2199.0,USD",
        "popularity":6,
        "inStock":true,
        "store":"43.17614,-90.57341",
        "_version_":1654893957917704192,
        "price_c____l_ns":219900
},
{
        "id":"VA902B",
        "name":"ViewSonic VA902B - flat panel display - TFT - 19\"",
        "manu":"ViewSonic Corp.",
        "manu_id_s":"viewsonic",
        "cat":["electronics and stuff2"],
        "features":["19\" TFT active matrix LCD, 8ms response time, 1280 x 1024 native resolution"],
        "weight":190.4,
        "price":279.95,
        "price_c":"279.95,USD",
        "popularity":6,
        "inStock":true,
        "store":"45.18814,-93.88541",
        "_version_":1654893957930287104,
        "price_c____l_ns":27995}]
  }

 

Solr 예제에서는 설명되지 않았지만 루씬 검색식에 있는 예제에 정리된 범위(Range)가 있다.

범위는 많이 사용하는 검색식(Query)으로

price:[* TO 100]은 가격(price)이 100($) 이하인 것,

price:[100 TO 500]은 100~500 사이인 것,

price:[100 TO *] 100보다 비싼 것을 검색하는 검색식이다.

보다 자세한 것은 루씬 검색식을 참고 하면 된다.

 

이러한 검색식들은 구글의 검색식과 비슷하게 제공되고,

다양하게 제공되니 예제를 익히고 나서 Solr 문서의 내용을 잘 읽어보길 바란다.

 

Solr 예제를 설치해서 검색하는 방법에 대해서 정의했고,

이번에는 검색을 위해 데이터를 저장하는 방법 중 구조(Schema)를 구성하는 것에 대해서 정리한다.

Solr 예제에서 영화 정보(films)를 이용하여 구조에 대해서 설명하기 때문에, 여기에서도 영화 정보를 이용하여 정리한다.

  1. 설치
  2. 기술제품과 검색식
  3. 스키마(Schema)
  4. DIH (Data Import Handler)

데이터를 저장하기 위해서는 저장하는 장소, 즉 스키마(Schema)에 대해서 정의해야 한다.

대부분의 데이터는 다음 엑셀 그림처럼 name, directed_by, genre, type, id, initial_release_date 같은 컬럼이 있고, 각각의 데이터가 행으로 저장된다.

각각의 컬럼이 어떤 데이터를 가지는 지를 정의하는 것이 스키마로 데이터 베이스(DBMS)의 용어와 동일한 의미로 사용된다.

그림을 보면 배포일자(initial_release_date)는 년월일의 년도 형 데이터 구조를 가지고 있다.

이 외의 모든 컬럼은 일반 (텍스트, 문자열) 형 데이터 구조를 가지고 있다.

숫자가 있었다면 숫자형 데이터를 가지게 된다.

이렇게 구조를 미리 지정해서 저장하는데, Solr에서는 이 스키마를 미리 정의하지 않고도 사용할 수 있다. 

Elasticsearch도 동일한데, 이것을 Schemaless라고 한다.

하지만, 가급적 정의해서 사용하는 것이 좋고, 그 이유를 Solr 예제에서 제공하고 있다.


Solr를 실행하고(solr star), 다음 명령어로 films 코어를 생성한다.

      bin/solr create -c films             <- Linux, Mac

      bin\solr delete -c films           <- Windows

 

예제 폴더(example)에는 앞서 정리한 기술제품(techproducts)외에도 영화 정보(films) 예제 파일이 있다.

이 파일의 내용을 생성한 films 코어에 저장한다.

다음 명령어로 생성한 films 코어에 데이터를 저장한다.

      bin/post -c films example/films/films.json                                                         <- Linux, Mac

      java -jar -Dc=films -Dauto example\exampledocs\post.jar example\films\*.json     <- Windows

영화 정보(films) 폴더에는 films.csv, films.json, films.xml 3개의 파일이 있다.

모두 동일한 영화 정보 데이터를 가지고 있고, 이 중에서 json 파일의 내용을 films 코어에 저장하는 명령어이다.

films 코어를 생성하고, 데이터를 저장하면 위 그림과 같이 오류가 발생한다.

그리고, Solr 관리자 화면에서 데이터를 조회(Query)하면, 5개의 데이터가 저장되어 있다.

화면을 스크롤 해서 이름(name) 필드의 값을 보면, 모두 실수형이고 배열 ([])이다.

  {
    "id":"/en/45_2006",
    ~~ 생략
    "name":[0.45],
  {
    "id":"/en/9_2005",
    ~~ 생략
    "name":[9.0],
  {
    "id":"/en/69_2004",
    ~~ 생략
    "name":[69.0],
  {
    "id":"/en/300_2007",
    ~~ 생략
    "name":[300.0],
    "_version_":1655399262942396417},
  {
    "id":"/en/2046_2004",
    ~~ 생략
    "name":[2046.0],
    "_version_":1655399262943444992}]
  }

Solr 관리자 화면의 스키마(Schema) 화면은 선택된 코어의 필드 구조를 관리 하는 페이지로,

name 필드를 선택하면 type이 pdoubles(실수) 로 생성되어 있다.

(이 화면에서 데이터가 저장되면서 자동으로 생성된 모든 필드들을 볼 수 있다.)

영화 예제 폴더 중에서 csv 파일을 엑셀로 열면, name (A)컬럼의 앞에 있는 5개 데이터가 숫자이다.

그리고, 6번째 데이터부터 약 1000개의 데이터는 문자이다.

Solr (실재로는 Lucene)에서는 첫 데이터로 컬럼의 구조를 정의하는데,

위와 같이 첫 데이터가 숫자면 컬럼은 숫자(실수)로 정의한다.

즉, 앞서의 데이터 저장시 발생한 오류는 숫자 컬럼에 문자가 입력되어 발생한 오류이다.

 

name 필드를 삭제하고 새로 생성해서, 이 오류를 해결한다.

Schema 페이지(앞서의 이미지)에서 name 필드를 선택하면 활성화 되는 하단의 [delete field] 버튼을 클릭해서 name 필드를 삭제한다.

그리고, 상단의 [Add Field] 버튼을 클릭하여 name 필드를 다시 생성한다.

그림과 같이 생성할 필드명 name을 입력하고, field type에는 문자열(text_general)을 지정하고 필드를 생성한다 (Add Field).

name 필드가 생성된 것을 확인하고, 앞서 실행했던 데이터 저장을 다시 실행하면(post),

그림과 같이 오류 없이 실행되는 것을 확인 할 수 있다.

Solr 관리자 페이지 Query 에서 데이터를 조회하면, 1100개의 데이터가 저장되어 있다.

Solr나 Elasticsearch에서는 이 스키마를 미리 정의하지 않고도 사용할 수 있지만(Schemaless)

이와 같이 데이터의 구조를 제대로 고려하지 않고 사용하면 문제가 발생하기 때문에 스키마를 정의해서 사용하는 것이 좋다.

이 문제 외에도 긴 문장의 경우에는 형태소 분석 등을 하게 된다.

이런 필드와 그냥 저장하는 필드 등을 미리 정의해야 해서 스키마를 미리 정의해서 사용하는 것이 좋다.

또다른 필드 추가 방법

Solr 관리자 화면에서 필드를 지우거나 생성해도 되고, 다음과 같이 RESTful로 처리해도 된다.

Linux: curl -X POST -H 'Content-type:application/json' --data-binary '{"delete-field" : { "name":"name" }}' http://localhost:8983/solr/films/schema
Windows: curl -X POST -H "Content-type:application/json" --data-binary "{\"delete-field\" : { \"name\":\"name\" }}" http://localhost:8983/solr/films/schema

curl 사용시 리눅스는 홑따옴표(')를 사용하고, 윈도우는 쌍따옴표(")를 사용하는 차이가 있다

윈도우는 쌍따옴표(")를 사용하기 때문에 Json 키/값 표현에 사용되는 쌍따옴표(")는 \"로 표현해야 한다.

필드를 삭제(delete-field) 할 때에는 삭제할 필드명(name)을 name으로 지정한다.

 

Linux: curl -X POST -H 'Content-type:application/json' --data-binary '{"add-field": {"name":"name", "type":"text_general", "multiValued":false, "stored":true}}' http://localhost:8983/solr/films/schema
Windows: curl -X POST -H "Content-type:application/json" --data-binary "{\"add-field\": {\"name\":\"name\", \"type\":\"text_general\", \"multiValued\":false, \"stored\":true}}" http://localhost:8983/solr/films/schema

필드를 추가(add-field) 할 때에는 필드명(name), 필드 타입(type), 다중값 여부(multiValued, 배열), 저장여부(stored)등을 지정해서 생성한다.

이와 관련된 정리는 다른 블로그에 잘 정리되어 있다.

{
    "add-field": {
                    "name":"name", 
                    "type":"text_general", 
                    "multiValued":false, 
                    "stored":true
                }
}        

이상과 같이 RESTful 방식으로 스키마를 생성하는 자세한 방법은 Solr 도움말을 참고 하면 된다.

 

스키마에 대해서 조금 더 정리하면,

적당한 편집기로 example\techproducts\solr\techproducts\conf 폴더에 있는 managed-schema 파일을 연다.

example\techproducts\solr\techproducts 폴더는 앞서 정리한 기술제품(techproducts)의 코어가 있는 폴더이고

managed-schema 파일은 코어의 스키마에 대해서 정의하는 XML 파일이다.

   <field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" /> 

   <field name="pre" type="preanalyzed" indexed="true" stored="true"/>
   <field name="sku" type="text_en_splitting_tight" indexed="true" stored="true" omitNorms="true"/>
   <field name="name" type="text_general" indexed="true" stored="true"/>
   <field name="manu" type="text_gen_sort" indexed="true" stored="true" omitNorms="true" multiValued="false"/>
   <field name="cat" type="string" indexed="true" stored="true" multiValued="true"/>
   <field name="features" type="text_general" indexed="true" stored="true" multiValued="true"/>
   <field name="includes" type="text_general" indexed="true" stored="true" termVectors="true" termPositions="true" termOffsets="true" />

   <field name="weight" type="pfloat" indexed="true" stored="true"/>
   <field name="price"  type="pfloat" indexed="true" stored="true"/>
   <field name="popularity" type="pint" indexed="true" stored="true" />
   <field name="inStock" type="boolean" indexed="true" stored="true" />

   <field name="store" type="location" indexed="true" stored="true"/>

앞서 정리했던, 기술제품(techproducts)의 필드들이 정의되어 있다.

필드명(name), 색인여부(indexed), 저장여부(indexed), 필수 입력(required), 다중값여부(multiValued)등의 속성을 지정했다.

이와 관련된 정리는 다른 블로그에 잘 정리되어 있다.

영화 정보의 managed-schema 파일 (\server\solr\films)에는 이러한 정의가 없다 (Schemaless).

 

 

'서버 > 검색엔진' 카테고리의 다른 글

1. Solr 예제 분석 - 설치  (1) 2020.01.12
2. Solr 예제 분석 - 기술제품과 검색식  (3) 2020.01.12
4. Solr 예제 분석 - DIH  (0) 2020.01.12
1. Solr로 만드는 단순 게시판: 각종 설치  (18) 2017.08.24
2. SolrJ 사용법  (0) 2017.08.24

마지막 예제 분석으로 DIH (Data Import Handler)를 정리한다.

앞서의 기술제품과 영화 예제들은 정리된 데이터를 저장(색인)한 것이고,

DIH는 원본 데이터에서 데이터를 추출해서 저장하는 방법에 대한 예제이다.

  1. 설치
  2. 기술제품과 검색식
  3. 스키마(Schema)
  4. DIH (Data Import Handler)

 

Solr 예제 폴더(example\example-DIH\)에는 atom, db, mail 등의 데이터 예제가 있다.

이 중에서 db (hsqldb) 예제를 정리한다.

주의: SQL이나 데이터 베이스에 대한 개념이 없다면, 다음 내용을 이해하는데 어려울 수 있다.


실행 중인 Solr를 멈추고,

      bin\solr stop -all

다음 명령어로 DIH 예제를 실행한다.

      bin\solr -e dih

Solr 관리자 화면으로 접속하면 5개의 코어가 생성된 것을 확인할 수 있다. 

이 중에서 db 코어를 선택하고, Query 화면에서 데이터를 조회하면 비어 있다 (numFound=0).

Solr 관리자 화면의 Dataimport 메뉴를 선택한 후, 화면 오른쪽의 Configuration을 클릭해서 실행할 SQL문을 확인한다.

중앙의 실행(Execute) 버튼을 클릭해서, 이 SQL문을 실행한다.

실행(Execute) 버튼을 클릭하고, Auto-Refresh Status를 체크해서 자동으로 갱신되게 하거나,

Refresh Status를 클릭해서 수동으로 갱신해서 처리 결과를 확인한다.

녹색 배경으로 16개의 데이터(document)가 저장되었다는 메시지가 나타나면, 잘 실행된 것이다.

Query 메뉴에서 저장된 데이터를 확인 할 수 있다.

앞서 정리한 기술 제품의 내용과 동일한 데이터로,

기술 제품 예제는 이 데이터 베이스의 내용을 XML로 만든 파일을 저장한 것이다.

 

간단하게 db 예제 사용법을 정리했고, 상세한 내용을 정리한다.

예제로 사용된 db는 hsqldb이지만

Dataimport 메뉴에서 확인한 다음의 SQL문을 보면 기본적인 SQL문만 사용되었기 때문에 hsqldb라는 것에 부담을 가질 필요는 없다.

<dataConfig>
    <dataSource driver="org.hsqldb.jdbcDriver" url="jdbc:hsqldb:${solr.install.dir}/example/example-DIH/hsqldb/ex" user="sa" />
    <document>
        <entity name="item" query="select * from item"
                deltaQuery="select id from item where last_modified > '${dataimporter.last_index_time}'">
            <field column="NAME" name="name" />

            <entity name="feature"  
                    query="select DESCRIPTION from FEATURE where ITEM_ID='${item.ID}'"
                    deltaQuery="select ITEM_ID from FEATURE where last_modified > '${dataimporter.last_index_time}'"
                    parentDeltaQuery="select ID from item where ID=${feature.ITEM_ID}">
                <field name="features" column="DESCRIPTION" />
            </entity>
            
            <entity name="item_category"
                    query="select CATEGORY_ID from item_category where ITEM_ID='${item.ID}'"
                    deltaQuery="select ITEM_ID, CATEGORY_ID from item_category where last_modified > '${dataimporter.last_index_time}'"
                    parentDeltaQuery="select ID from item where ID=${item_category.ITEM_ID}">
                <entity name="category"
                        query="select DESCRIPTION from category where ID = '${item_category.CATEGORY_ID}'"
                        deltaQuery="select ID from category where last_modified > '${dataimporter.last_index_time}'"
                        parentDeltaQuery="select ITEM_ID, CATEGORY_ID from item_category where CATEGORY_ID=${category.ID}">
                    <field column="DESCRIPTION" name="cat" />
                </entity>
            </entity>
        </entity>
    </document>
</dataConfig>

SQL이 나열된 XML은 Dataimport 메뉴에서 확인 할 수도 있고,

db-data-config.xml 설정(example\example-DIH\solr\db\conf)파일에서도 확인/ 수정 할 수 있다.

참고: Solr의 기본 설정 파일인 solrconfig.xml에서 다음과 같이 db-data-config.xml 을 지정해야 db-data-config.xml 에서 위와 같은 내용을 작성해서 사용할 수 있다.

 <lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-dataimporthandler-\d.*\.jar" />

생략

  <requestHandler name="/dataimport" class="solr.DataImportHandler">
    <lst name="defaults">
      <str name="config">db-data-config.xml</str>
    </lst>
  </requestHandler>

 

dataSource는 Java의 dataSource와 같은 것으로, 데이터베이스 접속에 필요한 driver, url과 id, password등을 입력한다.

예제에서는 sa 계정에 비밀번호없이 접속한다.

 

이상의 SQL문을 하나 하나 정리할 수는 없고, 개념으로 정리한다.

사용된 hsqldb의 테이블 구조를 알아야 사용된 SQL문을 이해하기 쉽다.

hsqldb의 테이블 구조와 데이터는 example\example-DIH\hsqldb 폴더에 있는 ex.script 파일에 정의되어 있다.

이 내용 중 테이블 정의와 관련된 내용을 ERD로 정리하면 다음 그림과 같다.

ITEM(제품) 테이블이 기술 제품의 핵심 테이블로, 제품의 특성(FEATURE) 및 종류(CATEGORY) 테이블과 1:n으로 연결된다.

제품 테이블의 ID가 기본키(Primary Key)로, 특성(FEATURE)과 종류(ITEM_CATEGORY) 테이블의 ITEM_ID 필드(Foregin Key)와 관계(Relation)를 가진다.

즉, 하나의 제품이 여러 개의 특성과 종류를 가진다.

ITEM_CATEGORY은 연관 테이블(Association Table)로 여러개의 종류를 가지기 위해 사용되었다

(데이터 베이스와 관계된 개념은 여기서는 정리하지 않는다.)

주의: 데이터베이스에서는 이와 같이 데이터를 정규화해서 저장하지만, 검색엔진에서는 하나의 데이터로 묶어서 저장한다.

 즉, 데이터베이스에서 1:n으로 구성한 데이터는 검색엔진에서 배열([ ]), 즉 multiValued로 저장한다.

 

dataSource 태그는 접속 정보를 입력하고,

document 태그는 처리할 데이터를 정의하는 태그로 기본 구조는 다음과 같다.

    <document>
        <entity name="item" query="select * from item"
                deltaQuery="select id from item where last_modified > '${dataimporter.last_index_time}'">
            <field column="NAME" name="name" />
        </entity>
    </document>		

문서(document)를 구성하는 것을 entity라고 한다.

이 entity는 처음에는 query에 지정된 데이터로 채우고, 이후에 증가된 데이터는 deltaQuery로 지정된 데이터로 채운다.

처음에는 기존에 있던 데이터에 대해서(query) 전체 색인을 진행하고(Full indexing), 이후에는 증가된 데이터만(deltaQuery) 색인하도록 작성한다.

즉, 처음에는 모든 제품을 가져오고 select * from item

마지막 색인을 한 시간(last_index_time) 이후에 추가된 제품(last_modified)만 조회해서 색인한다.

last_modified > '${dataimporter.last_index_time}'

 

이렇게 문서를 생성해서 저장(색인)하면 되지만,

앞서 ERD로 정리한 것처럼 기술 제품은 여러 개의 제품의 특성(FEATURE)과 종류(CATEGORY)를 가지고 있다.

이것을 그냥 Join으로 작성하면, 1:n의 관계를 가지기 때문에 하나의 제품이 여러 개 조회되는 문제가 생긴다.

 

제품 특성(FEATURE) 테이블을 예로 정리하면,

제품(item)을 가져오는 entity 태그 하위에(안에), 특성(feature)를 가져오는 entity 태그를 추가한다.

<entity name="item" query="select * from item"
    ~~ 생략 ~~
	<entity name="feature"  
			query="select DESCRIPTION from FEATURE where ITEM_ID='${item.ID}'"
			deltaQuery="select ITEM_ID from FEATURE where last_modified > '${dataimporter.last_index_time}'"
			parentDeltaQuery="select ID from item where ID=${feature.ITEM_ID}">
		<field name="features" column="DESCRIPTION" />
	</entity>
</entity>

ERD의 관계(Relation)를 태그의 하위 계층으로 표현하는 것이다.

 

특성(FEATURE) 테이블에서 데이터를 가지고 오는 것은 제품(ITEM) 테이블에서 가지고 오는 것과 동일하다.

처음에는(query) 테이블의 모든 데이터를 가지고 오고,

이후에는(deltaQuery) 증가된 데이터만 가지고 온다. last_modified > '${dataimporter.last_index_time} 

 

여기에 추가적인 것이 parentDeltaQuery로 부모가 누구인지 지정하는 부분이 있다.

가지고 온 데이터를 누구에게 넣어줄 것인지를 지정하는 것으로,

제품(ITEM) 테이블에서 ID 필드가 기본키(paimary key)로 특성(FEATURE)테이블의 ITEM_ID 필드로 관계가 설정되어 있어, 이 값으로 서로를 식별하게 된다.

        select ID from item where ID=${feature.ITEM_ID}

즉, 특성 테이블의 값을 가지고 온 후(feature), 제품 테이블의 해당하는 ID를 찾아서,

특성의 값(DESCRIPTION)을 features로 저장(색인)한다.

        <field name="features" column="DESCRIPTION" />

주의: item(최상위 entity)에서도 field 태그를 이용해서 NAME을 name으로 저장하도록 지정했다.

색인으로 저장할 컬럼들은 모두 field 태그로 지정해야 하고, managed-schema에 정의해야 한다.

DIH에서는 managed-schema에 지정되지 않은 컬럼은 저장되지 않는다.

앞서 정리한 Shemaless가 적용되지 않는 것 같다.

 

parentDeltaQuery로 표현된 방식은 중요한 개념이라 다시 정리하면,

일반적인 S/W 개발에서는 제품(ITEM) 테이블에서 데이터를 가지고 오고, 

각각의 행에 있는 제품의 특성(ID) 필드의 값에 맞는 것을 특성(FEATURE) 테이블에서 찾아서

해당하는 설명(DESCRIPTION)을 가지고 오게 작성한다. 

그리고 SQL로 표현하면 다음과 같다.

      select a.*, 
            (select DESCRIPTION from FEATURE where ITEM_ID=a.ID) as features
      from ITEM a

주의: 제품(ITEM)과 특성(FEATURE)의 관계는 1:n 이기 때문에 이 SQL문을 그대로 쓰면 오류가 발생해서 실제론 stragg 처리를 해야 한다.

일반적인 S/W 개발에서는 제품(ITEM) 데이터를 가지고 오면서, 필요한 구성원 데이터(특성-FEATURE)을 가지고 오도록 작성한다.

(모 상용 검색엔진이 이런식으로 사용한다.)

 

이 개념과 반대로, 예제에서는 제품(ITEM) 데이터를 가지고 와서 저장하고

필요한 구성원 데이터(FEATURE)를 가지고 와서 저장된 제품(ITEM)에 넣어주는 방식으로 작성되었다.

 

이렇게 하는 이유는 제품(ITEM)과 특성(FEATURE) 테이블로 설명하는 것은 부족한 것 같아서 게시판 예제로 정리한다.

게시판에 게시물이 있고(post), 하나의 게시물에 여러 개의 댓글(reply)이 달린다.

일반적인 S/W 개발 방식으로 데이터를 추출하면, 게시물이 색인 될 때의 댓글도 같이 색인하면 된다.

하지만, 색인 된 이후에 추가된 댓글들은 색인하기 어렵다.

따라서, 게시물은 게시물 데로 색인하고, 댓글은 댓글데로 색인해서

추가 댓글이 있으면 추출해서 해당 게시물에 넣어주는 것(parentDeltaQuery)이 더 좋은 방식일 것이다.


종류(category, item_category)도 동일한데, 연관 테이블(Association Table)이 있어서 좀 더 복잡하다.

원리는 동일하니 직접 확인하고, 여기에서는 정리 하지 않는다.

 

이상의 정리는 Solr DIH 예제를 정리한 것으로, 보다 상세한 내용은 Solr DIH 예제에 정리된 내용을 읽어보면 된다.

이상으로 기술 제품에 대해 검색하는 방법,

기술 제품과 영화 정보 구축을 위해 스카마를 구성하는 방법,

스키마에 맞춰서 데이터를 저장하는 방법(색인)을 Solr 예제로 정리하였다.

 

Solr 예제 문서에 빠진 내용은 색인을 진행하는 시간 처리로,

초기에 전체 데이터를 대상으로 진행하는 풀색인은 앞서 정리한 것처럼 Dataimport 메뉴에서 실행해도 되고, 다음과 같이 RESTful로 실행해도 된다.

       curl http://localhost:8983/solr/dih/dataimport?command=full-import

풀색인은 사람이 진행하지만,
증가되는 데이터는 실시간으로 색인하는 경우가 아니면, 지정된 시간에 증가된 데이터에 대해서만 진행한다(delta-import).

지정된 시간에 실행하기 위해 별도의 프로그램을 제작하거나 플러그인을(DataImportScheduler) 이용할 수 있는데,

Solr 문서에서는 운영체제의 스케쥴 기능을 이용하길 원하는 것 같다.

좋은 스케쥴 기능이 많다며, DataImportScheduler 같은 것을 사용하는 것은 바퀴를 다시 발명하는 것이라고 한다.

증분만 실행하는(delta-import) 다음 명령어를 crontab에 등록해서 지정된 시간에 실행되게 사용한다. 

        curl http://localhost:8983/solr/dih/dataimport?command=delta-import

 

이상의 내용 외에 사용자가 입력한 검색어를 Solr로 전송하고, 결과를 받아서 출력하는 프로그램(Java)에서 사용하는 SolrJ와

색인하는 방법에 대한 구체적인 내용은 정리하지 않았다.

SolrJ와 관련된 내용은 이전 블로그 내용을 참고하거나 다른 자료를 찾아보면 된다.

색인하는 방법은 한국어 등을 색인 하기 위해서 필요한 것으로 형태소 분석과 관련된 내용을 찾아보면 된다.

 

+ Recent posts