bootstrap.yml - search

spring:
  application:
    name: search
  # Config Server 설정
  config:
    import: configserver:<https://j12e202.p.ssafy.io/config>

  # Spring Cloud Bus 설정
  cloud:
    bus:
      enabled: true
      refresh:
        enabled: true

# Actuator 엔드포인트 설정
management:
  endpoints:
    web:
      exposure:
        include: health,info,refresh,busrefresh
  endpoint:
    health:
      show-details: never

.env (프론트)

VITE_KAKAO_REST_API_KEY=7537de3fcdc73bb8f2a04d8e785ff575
VITE_KAKAO_JAVASCRIPT_KEY=ed680779dd173900e3df5f89d2978195
VITE_KAKAO_REDIRECT_URI=http://localhost:5173/callback/kakao
VITE_BASE_URL=https://j12e202.p.ssafy.io

.env (백)

# elasticsearch config
ELASTIC_HOST=13.209.12.173
ELASTIC_PORT=9200
ELASTIC_USERNAME=
ELASTIC_PASSWORD=

application.yml - bank

spring:
  application:
    name: bank

  datasource:
    url: jdbc:mysql://localhost:3306/financial?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
    username: ssafy
    password: ssafy
    driver-class-name: com.mysql.cj.jdbc.Driver
    hikari:
      maximum-pool-size: 10
      minimum-idle: 5
      idle-timeout: 300000
      connection-timeout: 20000

financial:
  api:
    url: <https://finopenapi.ssafy.io/ssafy/api/v1>
    api-key: 1dd804560c3e42c8b7f9ac8bc6746517

application.yml - financial

spring:
  application:
    name: financial

  datasource:
    url: jdbc:mysql://localhost:3306/financial?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
    username: ssafy
    password: ssafy
    driver-class-name: com.mysql.cj.jdbc.Driver
    hikari:
      maximum-pool-size: 10
      minimum-idle: 5
      idle-timeout: 300000
      connection-timeout: 20000

financial:
  api:
    url: <https://finopenapi.ssafy.io/ssafy/api/v1>
    api-key: 1dd804560c3e42c8b7f9ac8bc6746517

escrow:
  account:
    number: 0012040343253243
    bank-code: 001

application.yml - search

spring:
  application:
    name: search

  # Elasticsearch 연결 정보
  config:
    elastic:
      host: 13.209.12.173
      port: 9200

  data:
    redis:
      host: localhost
      port: 6379

  batch:
    jdbc:
      initialize-schema: always # 스키마 자동 생성 (초기 개발 시만)
    job:
      enabled: false # 자동 실행 방지 (스케줄러로 수동 실행)

  datasource:
    url: jdbc:mysql://localhost:3306/keywi?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
    username: ssafy
    password: ssafy
    driver-class-name: com.mysql.cj.jdbc.Driver
    hikari:
      maximum-pool-size: 10
      minimum-idle: 5
      idle-timeout: 300000
      connection-timeout: 20000

client:
  feed-service:
    url: <http://localhost:8400>

mybatis:
  mapper-locations: classpath:mapper/**/*.xml
  type-aliases-package: com.ssafy.search.dto
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

server:
  port: 8200
  servlet:
    context-path: /
  tomcat:
    max-threads: 200
    min-spare-threads: 30

logging:
  level:
    com.ssafy: DEBUG
    org.springframework: INFO
    org.elasticsearch: INFO
    org.springframework.batch: DEBUG


Elasticsearch 쿼리

// 자동완성 검색어 제안
DELETE /search_suggest

GET search_suggest/_search

GET search_suggest/_mapping

GET /search_suggest/_search
{
  "size": 10,
  "query": {
    "match": {
      "name": {
        "query": " "
      }
    }
  }
}

PUT /search_suggest
{
  "settings": {
    "max_ngram_diff": 49,
    "analysis": {
      "filter": {
        "suggest_filter": {
          "type": "ngram",
          "min_gram": 1,
          "max_gram": 50
        }
      },
      "tokenizer": {
        "jaso_search_tokenizer": {
          "type": "jaso_tokenizer",
          "mistype": true,
          "chosung": false
        },
        "jaso_index_tokenizer": {
          "type": "jaso_tokenizer",
          "mistype": true,
          "chosung": true
        }
      },
      "analyzer": {
        "suggest_search_analyzer": {
          "type": "custom",
          "tokenizer": "jaso_search_tokenizer"
        },
        "suggest_index_analyzer": {
          "type": "custom",
          "tokenizer": "jaso_index_tokenizer",
          "filter": ["suggest_filter"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "adScore": {
        "type": "float"
      },
      "id": {
        "type": "keyword"
      },
      "isAd": {
        "type": "boolean"
      },
      "name": {
        "type": "text",
        "analyzer": "suggest_index_analyzer",
        "search_analyzer": "suggest_search_analyzer",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      },
      "searchCount": {
        "type": "integer"
      }
    }
  }
}

// SNS 피드 검색
DELETE /feeds

GET feeds/_search

GET feeds/_mapping

GET feeds/_search
{
  "query": {
    "match_all": {}
  },
  "_source": ["hashtags"]
}

GET feeds/_search
{
  "size": 10,
  "query": {
    "match": {
      "content": {
        "query": "eum"
      }
    }
  }
}

PUT /feeds
{
  "settings": {
    "max_ngram_diff": 49,
    "analysis": {
      "filter": {
        "suggest_filter": {
          "type": "ngram",
          "min_gram": 1,
          "max_gram": 50
        }
      },
      "tokenizer": {
        "jaso_search_tokenizer": {
          "type": "jaso_tokenizer",
          "mistype": false,
          "chosung": false
        },
        "jaso_index_tokenizer": {
          "type": "jaso_tokenizer",
          "mistype": false,
          "chosung": true
        }
      },
      "analyzer": {
        "suggest_search_analyzer": {
          "type": "custom",
          "tokenizer": "jaso_search_tokenizer"
        },
        "suggest_index_analyzer": {
          "type": "custom",
          "tokenizer": "jaso_index_tokenizer",
          "filter": ["suggest_filter"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "feedId": {
        "type": "keyword"
      },
      "content": {
        "type": "text",
        "analyzer": "suggest_index_analyzer",
        "search_analyzer": "suggest_search_analyzer"
      },
      "createdAt": {
        "type": "date"
      },
      "hashtags": {
        "type": "nested",
        "properties": {
          "name": {
            "type": "text",
            "analyzer": "suggest_index_analyzer",
            "search_analyzer": "suggest_search_analyzer"
          }
        }
      },
      "thumbnailUrl": {
        "type" : "keyword",
        "index": false
      },
      "taggedProducts": {
        "type": "nested",
        "properties": {
          "productId": { "type": "keyword" },
          "productName": {
            "type": "text",
            "analyzer": "suggest_index_analyzer",
            "search_analyzer": "suggest_search_analyzer"
          }
        }
      }
    }
  }
}

// 사용자 검색
DELETE /users

GET users/_search

GET users/_mapping

GET users/_search
{
  "query": {
    "match_all": {}
  },
  "_source": ["hashtags"]
}

GET users/_search
{
  "size": 10,
  "query": {
    "match": {
      "content": {
        "query": "eum"
      }
    }
  }
}

PUT /users
{
  "settings": {
    "max_ngram_diff": 49,
    "analysis": {
      "filter": {
        "suggest_filter": {
          "type": "ngram",
          "min_gram": 1,
          "max_gram": 50
        }
      },
      "tokenizer": {
        "jaso_search_tokenizer": {
          "type": "jaso_tokenizer",
          "mistype": false,
          "chosung": false
        },
        "jaso_index_tokenizer": {
          "type": "jaso_tokenizer",
          "mistype": false,
          "chosung": true
        }
      },
      "analyzer": {
        "jaso_index_analyzer": {
          "type": "custom",
          "tokenizer": "jaso_index_tokenizer",
          "filter": ["suggest_filter"]
        },
        "jaso_search_analyzer": {
          "type": "custom",
          "tokenizer": "jaso_search_tokenizer"
        },
        "ngram_en_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["lowercase", "suggest_filter"]
        },
        "standard_en_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["lowercase"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "userId":    { "type": "keyword" },
      "nickname":  {
        "type": "text",
        "fields": {
          "jaso": {
            "type": "text",
            "analyzer": "jaso_index_analyzer",
            "search_analyzer": "jaso_search_analyzer"
          },
          "ngram_en": {
            "type": "text",
            "analyzer": "ngram_en_analyzer"
          },
          "standard_en": {
            "type": "text",
            "analyzer": "standard_en_analyzer"
          }
        }
      },
      "profileContent":   { "type": "keyword" },
      "brix":        { "type": "integer" },
      "profileImageUrl":     { "type": "keyword", "index": false }
    }
  }
}

// 견적게시판 상품 태그 검색
DELETE /products_board

GET products_board/_search

GET products_board/_mapping

GET products_board/_search
{
  "size": 10,
  "query": {
    "match": {
      "productName": {
        "query": "케이스"
      }
    }
  }
}

GET /_cat/indices/products_board?v

PUT /products_board
{
  "settings": {
    "max_ngram_diff": 49,
    "analysis": {
      "filter": {
        "suggest_filter": {
          "type": "ngram",
          "min_gram": 1,
          "max_gram": 50
        }
      },
      "tokenizer": {
        "jaso_search_tokenizer": {
          "type": "jaso_tokenizer",
          "mistype": true,
          "chosung": false
        },
        "jaso_index_tokenizer": {
          "type": "jaso_tokenizer",
          "mistype": true,
          "chosung": true
        }
      },
      "analyzer": {
        "suggest_search_analyzer": {
          "type": "custom",
          "tokenizer": "jaso_search_tokenizer"
        },
        "suggest_index_analyzer": {
          "type": "custom",
          "tokenizer": "jaso_index_tokenizer",
          "filter": ["suggest_filter"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "productId":    { "type": "keyword" },
      "productName":  { 
        "type": "text", 
        "analyzer": "suggest_index_analyzer", 
        "search_analyzer": "suggest_search_analyzer" },
      "categoryId":   { "type": "keyword" },
      "categoryName": { "type": "keyword" },
      "price":         { "type": "integer" },
      "createdAt":    { "type": "date" },
      "imageUrl":     { "type": "keyword", "index": false }
    }
  }
}

// 전체 상품 검색 (sns 상품 태그 검색 재활용)
DELETE /products

GET products/_search

GET products/_mapping

GET products/_search
{
  "query": {
    "match_all": {}
  },
  "_source": ["hashtags"]
}

GET products/_search
{
  "size": 10,
  "query": {
    "match": {
      "content": {
        "query": "eum"
      }
    }
  }
}

PUT /products
{
  "settings": {
    "max_ngram_diff": 49,
    "analysis": {
      "filter": {
        "suggest_filter": {
          "type": "ngram",
          "min_gram": 1,
          "max_gram": 50
        }
      },
      "tokenizer": {
        "jaso_search_tokenizer": {
          "type": "jaso_tokenizer",
          "mistype": false,
          "chosung": false
        },
        "jaso_index_tokenizer": {
          "type": "jaso_tokenizer",
          "mistype": false,
          "chosung": true
        }
      },
      "analyzer": {
        "jaso_index_analyzer": {
          "type": "custom",
          "tokenizer": "jaso_index_tokenizer",
          "filter": ["suggest_filter"]
        },
        "jaso_search_analyzer": {
          "type": "custom",
          "tokenizer": "jaso_search_tokenizer"
        },
        "ngram_en_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["lowercase", "suggest_filter"]
        },
        "standard_en_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["lowercase"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "productId":    { "type": "keyword" },
      "productName":  {
        "type": "text",
        "fields": {
          "jaso": {
            "type": "text",
            "analyzer": "jaso_index_analyzer",
            "search_analyzer": "jaso_search_analyzer"
          },
          "ngram_en": {
            "type": "text",
            "analyzer": "ngram_en_analyzer"
          },
          "standard_en": {
            "type": "text",
            "analyzer": "standard_en_analyzer"
          }
        }
      },
      "categoryId":   { "type": "keyword" },
      "categoryName": { "type": "keyword" },
      "price":        { "type": "integer" },
      "createdAt":    { "type": "date" },
      "imageUrl":     { "type": "keyword", "index": false }
    }
  }
}

application.yml - mypage

server:
  port: 8080

spring:
  application:
    name: mypage-service

  datasource:
    url: jdbc:mysql://localhost:3306/keywi
    username: ssafy
    password: ssafy
    driver-class-name: com.mysql.cj.jdbc.Driver

  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

mybatis:
  mapper-locations: classpath:mapper/**/*.xml
  type-aliases-package: com.ssafy.mypage.profile.dto
  configuration:
    map-underscore-to-camel-case: true

logging:
  level:
    root: info
    com.ssafy: debug