{
"query" : {
"has_parent" : {
"type" : "group",
"query" : {
"match" : {
"_id" : "1"
}
}
}
}
}
JSON 에서는 별도의 datetype을 가지고 있지 않다. Elastic Search 에서 Date 타입을 표현하기 위한 방법은 아래와 같다.
내부적으로 날짜형식은 UTC 로 변경되고, 두번째 포맷으로 저장된다.
Date 포맷은 커스터마이징 될 수 있다. 만약 포맷이 지정되지 않는다면 아래와 같이 default로 동작한다.
"strict_date_optional_time||epoch_millis"
예를 들어 아래와 같은 코드가 있다고 가정한다.
0) The date field uses the default format.
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"date": {
"type": "date"
}
}
}
}
}
1) This document uses a plain date.
PUT my_index/my_type/1
{ "date": "2015-01-01" }
2) This document includes a time.
PUT my_index/my_type/2
{ "date": "2015-01-01T12:10:30Z" }
3) This document uses milliseconds-since-the-epoch
PUT my_index/my_type/3
{ "date": 1420070400001 }
4) Note that the sort values that are returned are all in milliseconds-since-the-epoch.
GET my_index/_search
{
"sort": { "date": "asc"}
}
기본적으로 필드 밸류들은 검색이 가능하도록 인덱싱이 된다.그러나 저장이 되진 않는다. 이것은 쿼리할 때 사용될 수 있어도 원 필드 값을 가져오는 것은 불가능하다는 것을 의미한다.
일반적으로 이건 문제가 되지 않는다. 필드 값은 _source 필드안에 이미 포함되어 있기 때문이다. 만약 당신이 개별 필드 혹은 일부의 값을 조회하길 원한다면 (_source의 전체 값 대신) _source 관련한 설정을 필터링할 수 있다. (ex. _source=false)
이러한 상황에 특정 필드의 store 하는 것은 합당하다. 예를 들어 당신이 만든 Document가 title, date, 큰 content 필드를 가지고 있다면 너는 큰 content 필드 빼고 title과 date 만 가져오길 원할 수 있다.
0) The title and date fields are stored.
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"title": {
"type": "text",
"store": true
},
"date": {
"type": "date",
"store": true
},
"content": {
"type": "text"
}
}
}
}
}
2) 데이터 입력
PUT my_index/my_type/1
{
"title": "Some short title",
"date": "2015-01-01",
"content": "A very long content field..."
}
3) title과 date 필드 정보만 가져온다.
GET my_index/_search
{
"stored_fields": [ "title", "date" ]
}
대부분의 필드는 기본적으로 검색가능하도록 인덱싱된다.
이런 인덱싱은 소팅이나, 집합 같은 연산에는 최적화 되어 있지 않다,
Doc Value는 디스크 기반은 자료구조이고, 인덱스 생성 시간에 만들어진다. 그 것은 같은 값을 _source에 저장한다.
만약 특정 필드에 대해서 소팅이나, 집합 연산이나 스크립트를 통한 접근이 필요 없다면, 디스크 공간을 아끼기 위하여 doc values를 disable 시킬수 있다.
인덱스 모듈은 인덱스 하나당 생성되는 모듈이고 인덱스와 관련한 속성을 컨트롤한다.
인덱스 세팅 하나에 관련하여 세팅할 수 있다. static - Close 상태나 생성시점에만 설정할 수 있다. dynamic - update-index-settings API를 통해서 변경할 수 있다.
index.max_result_window from + size 의 maximum value를 의미하고 default로는 10000입니다. 검색 요청은 from+size 크기에 비례해서 힙메모리를 증가시킵니다.
primary shard는 원본 데이터가 쪼개진 shard를 의미하고 replica shard는 primary shard 데이터 기준으로 복제된다.
해당 정보는 SKPlanet의 동영상을 보고 정리하였습니다.
▶ @EnableAsync 적용
@SpringBootApplication(scanBasePackages = "com.dasolute.simons")
@EnableAsync
public class SpringBootTestApplication {
}
▶ taskExecutor 생성
@Configuration
public class AsyncConfiguration {
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(2);
taskExecutor.setMaxPoolSize(8);
taskExecutor.setQueueCapacity(32);
return taskExecutor;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.2.xsd">
<!-- @async 사용을 위한 XML 설정 -->
<task:annotation-driven />
<task:executor id="messageTaskExecutor" pool-size="8" queue-capacity="100"/> <!-- 메시지 발송은 최대 8개로만 운영한다. -->
</beans>
위의 설정이 적용되면 spring task (schedule)과 관련한 annotation을 인식할 수 있다. @Async, @Scheduled 가 붙어 있는 Method나 Class를 비동기적인 수행을 하도록 한다.
Spring-Boot에서는 @EnableAsync, @EnableScheduling 을 통해서 활성화 시킬 수 있다.
@Async
public Future<String> service() {
return AsyncResult<>(result);
}
Future<String> f = myService.service();
String result = f.get()
ListenableFuture
# @Async with CompletableFuture
- Java 8에서 지원되는 비동기 Future
~~~java
@Async
public CompletableFuture<String> service() {
return CompletableFuture.completedFuture(result);
}
CompletableFuture<String> f = myService.service();
f.thenAccept(r->log.info("success", r));
ThreadPoolTaskExecutor 객체는 DisposableBean을 구현하고 있어서 Tomcat Instance가 종료되는 시점에 BeanFactory로부터 destory()가 호출되고 ExecutorConfigurationSupport 에 구현된 destory()에 의해서 executor.shutdown()이 호출된다.
public class ThreadPoolTaskExecutor
extends ExecutorConfigurationSupport
implements AsyncListenableTaskExecutor, SchedulingTaskExecutor {
}
public abstract class ExecutorConfigurationSupport
extends CustomizableThreadFactory
implements BeanNameAware, InitializingBean, DisposableBean {
public interface DisposableBean {
/**
* Invoked by a BeanFactory on destruction of a singleton.
* @throws Exception in case of shutdown errors.
* Exceptions will get logged but not rethrown to allow
* other beans to release their resources too.
*
* singleton 객체가 소멸되는 시점에 BeanFactory로부터 호출된다.
*/
void destroy() throws Exception;
}
public class MessageCallable implements Callable<List<Message>>{
private List<Message> messageList;
private MessageSendBO messageSendBO;
public MessageCallable(List<Message> messageList, MessageSendBO messageSendBO) {
this.messageList = messageList;
this.messageSendBO = messageSendBO;
}
@Override
public List<Message> call() throws Exception {
for (Message message : messageList) {
try {
messageSendBO.sendAsyncMessage(message);
} catch (Exception e) {
ExceptionCommonLogger.error(ExceptionPrefix.BATCH, e, message);
}
}
return messageList;
}
}
public Integer sendParallelMessageProcessing(List<Message> messageList, Integer executorPoolSize) {
Integer failCount = 0;
List<List<Message>> partitionedList = Lists.partition(messageList, partitionSizePerThread); // 최대 8개의 Thread 가 동작할 수 있는 적절한 값을 찾는다.
ExecutorService executor = Executors.newFixedThreadPool(executorPoolSize); // Poll 생성
List<Future<List<Message>>> futureList = Lists.newArrayList();
/** 비동기 수행 */
for (List<Message> eachList : partitionedList) {
Callable<List<Message>> worker = new MessageCallable(eachList, messageSendBO);
Future<List<Message>> submit = executor.submit(worker);
futureList.add(submit);
}
/** future.get() */
for (Future<List<Message>> future : futureList) {
future.get();
}
/** safely shutdown */
try {
executor.shutdown();
int tryCount = 0;
while (!executor.isTerminated()) {
executor.awaitTermination(1, TimeUnit.SECONDS);
/** 10번 이상 수행시에 강제종료*/
if (tryCount++ > 10) {
executor.shutdownNow();
break;
}
}
log.info("finished");
} catch (InterruptedException e) {
executor.shutdownNow();
}
return failCount;
}
작성중입니다.
이 아티클은 자바에서 어떻게 병렬프로그래밍을 할 수 있는지 설명합니다.
parallel programming, immutability, thread, executor framework (thread Pool),
futures, callables, CompletableFuture, fork-join 프레임워크 등에 대해 설명합니다.
Concurrency 는 여러 프로그램을 동시에 실행할 수 있는 능력 혹은 프로그램의 여러 부분을 병렬적으로 수행할 수 있는 능력을 의미한다. 만약 시간을 소비하는 Task가 병렬적으로 혹은 비동기적으로 실행될 수 있다면, 프로그램의 인터렉티브한 부분과 처리량을 증진시킬수 있다.
현대 컴퓨터는 여러개의 CPU, 여러개의 Core를 가진 CPU를 가지고 있다. 멀티코어는 큰 볼륨의 어플리케이션을 만드는데 중요한 요소가 될 수 있다.
프로세스는 독립적으로 수행되고 다른 프로세스와는 독립적이다. 프로세스는 다른 프로세스와 직접적으로 데이터를 공유할 수 없다. 메모리, CPU 시간 같은 자원은 OS를 통해 할당받는다.
스레드는 light-weight 프로세스라고도 불리운다. 각각의 Call Stack을 지니고 있다. 동일한 프로세스 내에서는 프로세스의 자원을 다른 스레드와 같이 접근할 수 있다. 모든 스레드는 각자 메모리 캐쉬를 가지고 있다. 만약 한 스레드가 공유한 자원을 읽는다면 그 스레드는 본인의 메모리 캐쉬에 저장한다. 스레드는 공유자원을 다시 Read 할 수 있다.
자바에서는 병렬 프로세싱 이나 비동기적인 행동을 하기 위해서 여러개의 스레드를 운영할 것이다. 하나의 Task가 여러 개의 subtask로 나뉠수 있고, 각각의 subtask는 병렬적으로 수행될 것이다.
이론적으로 획득 가능한 성능 지표는 Amdahl’s Law 에 의해 계산될 수 있다.
(skip)
스레드는 각각의 call Stack을 가지고 있지만, 프로세스의 공유 자원에도 접근이 가능합니다. 그래서 visibility, access 문제가 존재합니다.
visibility 는 A Thread가 공유자원을 읽은 후에 B가 공유자원에 변경을 일으키면, A는 이를 알지 못한다는 점을 의미한다. access 문제는 동시에 공유자원을 변경하는 부분이 문제가 된다.
자바는 thread 개념을 자바언어의 Thread 클래스를 통해서 지원한다. 자바는 해당 클래스를 통해 새로운 Thread를 생성할 수 있다.
Java 1.5부터는 java.util.concurrency Package를 통해서 비동기에 대한 지원이 더 강화되었다.
자바는 동시에 여러 스레드에 의해 수행되는 코드 블락을 보호하려고 lock 을 제공한다. 제일 간단한 locking 방법은 자바 클래스나 메소드에 synchronized 키워드를 사용하는 것이다.
synchronized 키워드는 아래를 보장한다.
public synchronized void critial() {
// some thread critival stuff
// here
}
당신은 메소드 안에서도 코드블락을 보호하기 위하여 synchronized 키워드를 사용할 수 있다. 이 블락은 키에 의해 보호되는데 이 키는 String 이거나 Object 이다. 이 키는 lock 이라고 불린다.
동일한 lock에 의해 보호되는 모든 코드는 동시에 오직 한 스레드에 의해서만 수행될 수 있다.
예를 들어서 아래 자료구조는 오직 한 스레드만 add(), next() 메소드를 접근 할 수 있도록 보장한다.
public class CrawledSites {
private List<String> crawledSites = new ArrayList<String>();
private List<String> linkedSites = new ArrayList<String>();
public void add(String site) {
synchronized (this) {
if (!crawledSites.contains(site)) {
linkedSites.add(site);
}
}
}
/**
* Get next site to crawl. Can return null (if nothing to crawl)
*/
public String next() {
if (linkedSites.size() == 0) {
return null;
}
synchronized (this) {
// Need to check again if size has changed
if (linkedSites.size() > 0) {
String s = linkedSites.get(0);
linkedSites.remove(0);
crawledSites.add(s);
return s;
}
return null;
}
}
}
(skip)
Java 메모리 모델은 어플리케이션의 메인 메모리와 각 스레드의 메모리 간의 커뮤니케이션을 설명한다. 스레드에 의해 수행된 메모리의 변경이 다른 스레드로 전파되는 방식에 대한 규칙을 정의합니다.
또한 Java 메모리 모델은 스레드가 메인 메모리에서 각 스레드의 메모리를 re-fresh 하는 상황을 정의합니다. 또한 원자적인 Operation과 Orderation의 순서도 설명합니다.
Atomic Operation이란 다른 Operation의 간섭가능성 없이 단일 unit으로 수행하는 operation을 의미합니다.
자바 언어 스펙은 변수를 읽거나 쓰는 것을 Atomic 하게 보장합니다. (long, double 타입이 아닌 경우에만)
long, double 자료형은 volatile
키워드와 함께 선언되어야만 Atomic 하게 움직입니다.
i 가 int 형으로 선언되어 있다고 가정한다. i++ 연산은 자바에서 원자적인 연산이 아니다. 이것은 다른 numeric 자료형에서도 적용된다.
i++ 연산은 먼저 i에 현재 저장되어 있어 있는 값을 읽고(원자적), 그리고 1을 더합니다.(원자적) 그러나 읽고 쓰는 사이에서 i의 값이 변경되었을 수도 있습니다.
Java 1.5 부터는 자바는 원자적 변수를 제공합니다. (AtomicInteger, AtomicLong) 원자적인 연산을 위해 getAndDecrement(), getAndIncrement() 등의 메소드를 제공합니다.
자바 메모리 모델은 syncronized 블락에 진입한 각각의 스레드가 동일한 잠금에 의해서 보호된 이전 변경사항의 영향을 받는것을 보장합니다.
동시성 문제를 피하는 가장 간단한 방법은 스레드간에 불변 데이터만 공유하는 것이다. 불편데이터는 변경할 수 없는 데이터를 의미한다.
클래스를 불편으로 만들기 위해서는
불변 클래스는 그 상태를 관리하기 위해서 몇 개의 변경 가능한 데이터도 포함할 수 있습니다. 그러나 외부로부터. 클래스의 속성은 변경될 수 있습니다.
본 글은 사내 TDD 교육 과정의 흔적입니다.
OUT -> IN 방식으로 도전
메모 API 테스트를 만든다 메모목록을 조회할수 있다 테스트 생성 LiveNote
JUNIT 스타일 (Assert.assertEquals()) assertThat 스타일
URI 자체가 없는것 = 404 URI 는 있으나 http method 방식이 없는 상황 = 405 서버 내부 오류 = 500
하이버네이트에서 중간에 Fassion 이라는 개념이 있다. insert 시점이 명확하지 않을 때는 강제로 insert 수행한다. clearAndFlush()
Dependency Breaking -> Double(대역사용) -> Seam?
Activity(UI) 테스트 단위테스트는 조금 정교하게 통합테스트는 하나 정도 만들어서 외부 API에 대한 테스트를 구성한다.
setter를 통해서 Seam을 만들었다 (이것은 틈이라고 볼수 있다.) 그리고 대역(double)을 setter를 통해 주입한다.
디펜덴시가 늘어나는 경우에 대해서 어떻게 고민을 해야하는가? 객체지향의 핵심 각자 책임을 가지고
아래 레퍼런스의 lombok-intellij-plugin 항목의 링크를 천천히 따라하면 됩니다.
AnnotationProcessor를 이용하여 컴파일 시점에 코드를 생성한다. 배포 시점에 lombok-1.16.xx.jar 파일이 존재하면 javac 가 동작하는 시점에 바이너리 코드가 생성된다.
javax.annotation.processing 패키지