#/**───────────────────────────────────────────────────────────
#
# 오타교정어
#
#───────────────────────────────────────────────────────────*/
# ─── 오타교정어 생성
PUT typo_correction
{
"mappings":{
"properties":{
"right_word":{
"type" : "keyword"
},
"wrong_words":{
"type":"nested",
"properties":{
"wrong_words":{
"type":"keyword"
}
}
}
}
}
}
# ─── 오타교정어 단건 INSERT
PUT typo_correction/_bulk
{"index" : {}}
{"right_word":"짜장","wrong_words":{"wrong_words":["쨔장","차장"]}}
# ─── 오타교정어 검색
GET typo_correction/_search
{
"query": {
"nested": {
"path": "wrong_words",
"query": {
"bool": {
"must": [
{
"match": {
"wrong_words.wrong_words": "참봉"
}
}
]
}
}
}
},"size":1
}
# ─── 조회된 레코드 삭제
POST typo_correction/_delete_by_query
{
"query": {
"bool": {
"must": [
{
"match": {
"right_word": "짬뽕"
}
}
]
}
}
}
# ─── 오타교정어 삭제
DELETE typo_correction
#/**───────────────────────────────────────────────────────────
#
# 인기검색어
#
#───────────────────────────────────────────────────────────*/
# ─── 인기검색어 생성
PUT popular
{
"mappings":{
"properties":{
"date":{
"type":"integer"
},
"index":{
"type":"keyword"
},
"keyword":{
"type":"keyword"
},
"search_time":{
"type":"integer"
},
"time":{
"type":"long"
}
}
}
}
# ─── 인기검색어 단건 INSERT
PUT popular/_bulk
{"index" : {}}
{"keyword" : "코스프레", "index" : "covid", "date" :20230402 , "search_time" : 141130 , "time" : 20230402141130}
# ─── 시간 인기검색어 조회
GET popular/_search
{
"query":{
"bool":{
"must":[
{
"bool":{
"should":[
{
"match":{
"keyword":"코스프레"
}
}
]
}
},
{
"bool":{
"filter":[
{
"range":{
"time":{
"lte":"20230402141130"
}
}
},
{
"range":{
"time":{
"gte":"20230402133056"
}
}
}
]
}
},
{
"bool":{
"should":[
{
"match":{
"index":"covid"
}
}
]
}
}
]
}
},
"size":10,
"aggs":{
"keyword":{
"terms":{
"field":"keyword"
}
}
}
}
# ─── 날짜 인기검색어 조회
GET popular/_search
{
"query":{
"bool": {
"filter": [
{ "range": { "date": { "gte": "20211220" }}}
]
}
},
"size": 0,
"aggs": {
"keyword": {
"terms": {
"field": "keyword"
}
}
}
}
# ─── 조회된 레코드 삭제
POST popular/_delete_by_query
{
"query": {
"bool": {
"must": [
{
"match": {
"keyword": "종식"
}
},
{
"match": {
"index": "covid"
}
}
]
}
}
}
# ─── 인기검색어 삭제
DELETE popular
#/**───────────────────────────────────────────────────────────
#
# 자동완성어
#
#───────────────────────────────────────────────────────────*/
# ─── 자동완성어 생성
PUT auto_keyword
{
"mappings":{
"properties":{
"auto_keyword":{
"type":"keyword"
},
"count":{
"type":"integer"
}
}
}
}
# ─── 자동완성어 단건 INSERT
PUT auto_keyword/_bulk
{"index" : {}}
{"auto_keyword" : "금칙어"}
# ─── 자동완성어 조회
GET auto_keyword/_search
{
"query": {
"prefix": {
"auto_keyword": {
"value": "코로나"
}
}
},
"collapse":{"field":"auto_keyword"},
"sort" : [
{ "count": "desc" }
]
}
# ─── 조회된 레코드 삭제
POST auto_keyword/_delete_by_query
{
"query": {
"match": {
"auto_keyword": "코로나도"
}
}
}
# ─── 자동완성어 삭제
DELETE auto_keyword
#/**───────────────────────────────────────────────────────────
#
# 금칙어
#
#───────────────────────────────────────────────────────────*/
# ─── 금칙어 생성
PUT forbidden
{
"mappings":{
"properties":{
"forbidden_word":{
"type":"keyword"
}
}
}
}
# ─── 금칙어 단건 INSERT
PUT forbidden/_bulk
{"index" : {}}
{"forbidden_word" : "금칙어"}
# ─── 금칙어 조회
GET forbidden/_search
{
"query": {
"term": {
"forbidden": {
"value": "금칙어"
}
}
}
}
# ─── 조회된 레코드 삭제
POST forbidden/_delete_by_query
{
"query": {
"match": {
"forbidden_word": "코로나도"
}
}
}
# ─── 금칙어 조회
DELETE forbidden
#/**───────────────────────────────────────────────────────────
#
# 기본 사전 고도화 분석
#
#───────────────────────────────────────────────────────────*/
PUT normal_dictionary_analyzer
{
"settings":{
"analysis":{
"tokenizer":{
"korean_nori_tokenizer":{
"type":"nori_tokenizer",
"decompound_mode":"none"
}
},
"analyzer":{
"nori_analyzer":{
"tokenizer":"korean_nori_tokenizer",
"filter":[
"nori_posfilter"
]
}
},
"filter":{
"nori_posfilter":{
"type":"nori_part_of_speech",
"stoptags":[
"J",
"SP", "SSO", "SSC", "SH", "SF", "SE", "SC", "SY"
]
}
}
}
}
}
# ─── 기본 사전 고도화 분석기 재기동(신조어 즉시 적용)
POST normal_dictionary_analyzer/_close
POST normal_dictionary_analyzer/_open
# ─── 기본 사전 고도화 분석기 삭제
DELETE normal_dictionary_analyzer
# ─── 기본 사전 고도화 분석기 정보 조회
GET normal_dictionary_analyzer/_settings
# ─── 기본 사전 고도화 분석기 문장 상세 분석
GET normal_dictionary_analyzer/_analyze
{
"analyzer": "nori_analyzer",
"text":"고소득자",
"attributes": ["leftPOS", "rightPOS"],
"explain": true
}
# ─── 기본 사전 고도화 분석기 문장 분석
GET normal_dictionary_analyzer/_analyze
{
"analyzer": "nori_analyzer",
"text": ""
}
#/**───────────────────────────────────────────────────────────
#
# 기본 인덱스 생성
#
#───────────────────────────────────────────────────────────*/
# ─── 인덱스 재기동(신조어 즉시 적용)
POST sample/_close
POST sample/_open
# ─── 인덱스 정보 조회
GET sample/_settings
# ─── 분석기 삭제
DELETE sample
# ─── 일반 인덱스 / 분석기 생성 [기본 분석기]
PUT sample
{
"settings":{
"analysis":{
"tokenizer":{
"korean_nori_tokenizer":{
"type":"nori_tokenizer",
"decompound_mode":"none",
"user_dictionary":"dictionary/newly_coined_word/user_dictionary.txt"
}
},
"analyzer":{
"nori_analyzer":{
"tokenizer":"korean_nori_tokenizer",
"filter":[
"nori_posfilter"
]
}
},
"filter":{
"nori_posfilter":{
"type":"nori_part_of_speech",
"stoptags":[
"J",
"SP", "SSO", "SSC", "SH", "SF", "SE", "SC", "SY"
]
}
}
}
}
}
# ─── 분석기 문장 상세 분석
GET sample/_analyze
{
"analyzer": "nori_analyzer",
"text":"사용한다",
"explain": true
}
# ─── 분석기 문장 분석
GET sample/_analyze
{
"analyzer": "nori_analyzer",
"text":"사용한다"
}
#/**───────────────────────────────────────────────────────────
#
# 인덱스 정보
#
#───────────────────────────────────────────────────────────*/
# ─── 형태소 분석기
GET covid/_analyze
{
"analyzer": "nori_analyzer",
"text":"재발견",
"explain": true
}
# ─── 스코어 확인하기
PUT score/_doc/1
{
"contents": "대구·경북 폭염특보…폭염 종합 대책 실시 [KBS 대구] .. ..[앵커] .. .. 오늘 절기상 가장 덥다는 대서인데요, .. .. 연일 무더운 날씨가 이어지면서 대구.경북에도 보름째 폭염특보가 이어지고 있습니다. .. .. 취재기자 연결합니다. .. .. 윤희정 기자,.. 대구시는 코로나 상황을 감안해 실내 무더위 쉼터 대신 강변이나 공원 등에 실외 무더위 쉼터 4백여 곳을 조성했습니다. .."
}
#/**───────────────────────────────────────────────────────────
#
# 검색 옵션
#
#───────────────────────────────────────────────────────────*/
# ─── 특정 필드만 출력 DSL (title 필드, company 필드만 노출)
# ─── select=title,company
GET covid/_search
{
"fields": [
"title",
"company"
],
"_source": false
}
# ─── 10000건 이상의 결과를 주기 위한 옵션
GET auto_keyword/_search
{
"track_total_hits": true
}
# ─── offset 및 limit
# ─── 시작 인덱스 위치 및 보여줄 개수 제한 (0번째 인덱스로부터 30개 보여주기)
# ─── offset=0&limit=30
GET covid/_search
{
"from" : 0,
"size" : 30
}
#/**───────────────────────────────────────────────────────────
#
# 검색
#
#───────────────────────────────────────────────────────────*/
# ─── anyword
# ─── 키워드 or 조건절 (마스크가 있거나 덴탈이 있어야한다.)
# ─── contents = "마스크 덴탈" anyword
GET covid/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"contents": "마스크 덴탈"
}
}
]
}
}
}
# ─── allword
# ─── 키워드 and 조건절 (마스크도 있고 덴탈도 있어야한다.)
# ─── contents = "마스크 덴탈" allword
GET search/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"contents": {
"query" : "그린",
"operator" : "and"
}
}
}
]
}
}
}
# ─── and
# ─── 같은 키워드 and 조건절 (contents의 코로나가 포함되면서 title의 코로나가 포함)
# [두개 필드에 키워드가 둘다 존재해야 함]
# ─── contenst = '코로나' and title = '코로나'
GET covid/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"contents": "코로나"
}
},
{
"match": {
"title": "코로나"
}
}
]
}
}
}
# ─── 멀티 필드 allword
# ─── 키워드 and 조건절 (contents에 폭염과 더위가 있어야하거나 + title에 폭염과 더위가 있어야한다.)
# ─── contents,title = '폭염 더위' allword
GET covid/_search
{
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "폭염 더위",
"fields": ["contents", "title"],
"operator": "and"
}
}
]
}
}
}
# ─── 멀티 필드 anyword
# ─── 키워드 or 조건절
# (contents에 폭염 또는 더위가 있어야하거나 + title에 폭염 또는 더위가 있어야한다.)
# [두개 필드에 키워드가 둘다 존재해야 함]
# ─── contents, title = '폭염 더위' anyword
GET covid/_search
{
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "폭염 더위",
"fields": ["contents", "title"]
}
}
]
}
},
"highlight":{
"pre_tags":["<em>"],
"post_tags":["</em>"],
"fields":{
"contents":{},
"title" : {}
}
}
}
# ─── 멀티 필드 anyword와 다른점 = (멀티 필드 anyword는 contents 또는 title 중에서 스코어가 높은게 위로가지만 or절로 묶은 건 스코어를 합산한다.)
# ─── contents, title = '폭염 더위' anyword
# vs
# (contents = '폭염 더위' anyword) or (title = '폭염 더위')
GET covid/_search
{
"size" : 80,
"query": {
"bool": {
"should": [
{
"multi_match": {
"query": "폭염 더위",
"fields": ["contents"]
}
},
{
"multi_match": {
"query": "폭염 더위",
"fields": ["title"]
}
}
]
}
}
}
# ─── (contents, title = "코로나" allword and wirter="윤희정" anyword)
# or
# (contents, title = "코로나" allword and writer = "박종일" anyword)
GET covid/_search
{
"query": {
"bool": {
"should": [
{
"bool": {
"must": [
{
"multi_match": {
"query": "코로나",
"fields": ["contents", "title"],
"operator": "and"
}
},
{
"multi_match": {
"query": "윤희정",
"fields": ["writer"]
}
}
]
}
},
{
"bool": {
"must": [
{
"multi_match": {
"query": "코로나",
"fields": ["contents", "title"],
"operator": "and"
}
},
{
"multi_match": {
"query": "박종일",
"fields": ["writer"]
}
}
]
}
}
]
}
}
}
# ─── (contents, title = "코로나" allword and wirter="박종일" anyword)
# and
# (contents, title = "코로나" allword and company != "KBS")
GET covid/_search
{
"query": {
"bool": {
"filter": [
{ "range": { "reg_date": { "gte": "20221220" }}}
],
"must": [
{
"bool": {
"must": [
{
"multi_match": {
"query": "코로나",
"fields": ["contents", "title"],
"operator": "and"
}
},
{
"multi_match": {
"query": "박종일",
"fields": ["writer"]
}
}
]
}
},
{
"bool": {
"must": [
{
"multi_match": {
"query": "코로나",
"fields": ["contents", "title"],
"operator": "and"
}
}
],
"must_not": [
{
"multi_match": {
"query": "KBS",
"fields": ["company"]
}
}
]
}
}
]
}
}
}
#/**───────────────────────────────────────────────────────────
#
# 구간 조회
#
#───────────────────────────────────────────────────────────*/
# ─── range = reg_date > 20221226
GET covid/_search
{
"query": {
"bool": {
"filter": [
{ "range": { "reg_date": { "lte": "20221226" }}}
]
}
}
}
# ─── 멀티 필드 allword + 날짜 조회
# (날짜는 무조건 구간이여야한다 <--- | | ----> 이딴식 불가능)
# ─── 키워드 and 조건절
# (contents에 폭염과 더위가 있어야하거나 title에 폭염과 더위가 있어야한다.)
# ─── contents, title = "폭염 더위" allword & range = reg_date > 20221226
GET covid/_search
{
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "폭염 더위",
"fields": ["contents", "title"],
"operator": "and"
}
}
],
"filter": [
{ "range": { "reg_date": { "gte": "20221206" }}},
{ "range": { "reg_date": { "lte": "20221222" }}}
]
}
}
}
#/**───────────────────────────────────────────────────────────
#
# 정렬 (type이 integer여야한다)
#
#───────────────────────────────────────────────────────────*/
# ─── order = reg_date asc
GET covid/_search
{
"sort" : [
{ "reg_date": "asc" }
]
}
# ─── order = reg_date asc
GET covid/_search
{
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "폭염 더위",
"fields": ["contents", "title"],
"operator": "and"
}
}
]
}
},
"sort" : [
{ "reg_date": "asc" }
]
}
#/**───────────────────────────────────────────────────────────
#
# 하이라이팅
#
#───────────────────────────────────────────────────────────*/
# ─── highlight-start=<em>&highlight-end=</em>&highlight-fields=contents
GET covid/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"contents": "마스크 덴탈"
}
}
]
}
},
"highlight":{
"pre_tags":["<em>"],
"post_tags":["</em>"],
"fields":{
"contents":{}
}
}
}
──── 검색엔진 셋팅 ────
1. sudo vi /etc/security/limits.conf
2. 하기 내용 추가
my_search soft memlock unlimited
my_search soft fsize unlimited
my_search hard nofile 65536
my_search soft nofile 65536
my_search hard nproc 65536
my_search soft nproc 65536
3. sudo vi /etc/sysctl.conf
4. 하기 내용 추가
vm.max_map_count=262144
─── fargate 적용 시 셋팅 값
1. vi ${설치경로}/es/elastic/config/elasticsearch.yml
2. 하기 내용 추가
node.store.allow_mmap: false
transport.host: localhost
transport.tcp.port: 9300
─── 검색엔진 Dockerfile 내용 ───
FROM company/my_search:1.1
USER search
EXPOSE 9200
EXPOSE 8021
WORKDIR /home
CMD ./start.sh
───────────────────
─── start.sh 내용 ───
${설치경로}/service/bin/startup.sh
${설치경로}/es/elastic/bin/elasticsearch
───────────────────
참고자료
- 유사도 기능 구현
- 실시간 동의어 적용
- 쿼리를 이용해 인덱스 도큐먼트 UPDATE
- 다양한 자동완성 기능 활용
'[ELK]' 카테고리의 다른 글
[ELK] 엘라스틱(Elastic) 노리 형태소 분석기 [노리분석기 Nori] (형태소 분석(상세), 불용어[Stopwords], 동의어[Synonym], open, close) (0) | 2022.09.12 |
---|---|
[ELK] 엘라스틱(Elastic) 인덱스 CRUD [노리분석기 Nori] (0) | 2022.09.12 |