반응형

Spark scala.reflect.api.JavaUniverse.runtimeMirror 에러


Exception in thread "main" java.lang.NoSuchMethodError: scala.reflect.api.JavaUniverse.runtimeMirror(Ljava/lang/ClassLoader;)Lscala/reflect/api/JavaMirrors$JavaMirror;

        at com.payco.dmp.orc.converter.ClickerScala$.main(ClickerScala.scala:36)

        at com.payco.dmp.orc.converter.ClickerScala.main(ClickerScala.scala)

        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

        at java.lang.reflect.Method.invoke(Method.java:498)

        at org.apache.spark.deploy.SparkSubmit$.org$apache$spark$deploy$SparkSubmit$$runMain(SparkSubmit.scala:743)

        at org.apache.spark.deploy.SparkSubmit$.doRunMain$1(SparkSubmit.scala:187)

        at org.apache.spark.deploy.SparkSubmit$.submit(SparkSubmit.scala:212)

        at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:126)

        at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)



spark-submit으로 spark 작업 실행 다음과 같은 에러 메세지가 떨어졌다면 build.sbt scala버전과 spark library 버전이


서버에서 사용중인 spark 버전과 맞는지 확인하기 바란다.


나의 경우는 spark2.1.1 에서 동작하는 scala spark프로젝트 내부 scalaVersion 2.10.5에서 2.11.5 변경하여 해결하였다.



반응형
반응형

Scala 버전만 작성하였다.


Java, Python, R에 대해서도 정보가 필요하다면 글 하단의 참조 링크를 참고 바란다.


SparkConf( Spark 1.6 / Spark 2.x)

You will continue to use these classes (via the sparkContext accessor) to perform operations that require the Spark Core API, such as working with accumulators, broadcast variables, or low-level RDDs. However, you will not need to manually create it.

// Spark 1.6
val sparkConf = new SparkConf().setMaster("local[*]")
sparkConf.set("spark.files", "file.txt")
 
// Spark 2.x
val spark = SparkSession.builder.master("local[*]").getOrCreate()
spark.conf.set("spark.files", "file.txt")


SparkContext( Spark 1.6 / Spark 2.x)

The SQLContext is completely superceded by SparkSession. Most Dataset and DataFrame operations are directly available in SparkSession. Operations related to table and database metadata are now encapsulated in a Catalog (via the catalog accessor).

// Spark 1.6
val sparkConf = new SparkConf()
val sc = new SparkContext(sparkConf)
val sqlContext = new SQLContext(sc)
val df = sqlContext.read.json("data.json")
val tables = sqlContext.tables()
 
// Spark 2.x
val spark = SparkSession.builder.getOrCreate()
val df = spark.read.json("data.json")
val tables = spark.catalog.listTables()


HiveContext( Spark 1.6 / Spark 2.x)

The HiveContext is completely superceded by SparkSession. You will need enable Hive support when you create your SparkSession and include the necessary Hive library dependencies in your classpath.

// Spark 1.6
val sparkConf = new SparkConf()
val sc = new SparkContext(sparkConf)
val hiveContext = new HiveContext(sc)
val df = hiveContext.sql("SELECT * FROM hiveTable")
 
// Spark 2.x
val spark = SparkSession.builder.enableHiveSupport().getOrCreate()
val df = spark.sql("SELECT * FROM hiveTable")


ref : https://sparkour.urizone.net/recipes/understanding-sparksession/

반응형
반응형

데이터 엔지니어로 살아가기 149일째(spark2.1.1


오늘 문득 spark2.1.1버전에서 java8 람다식을 활용한 데이터 처리 속도와 


spark1.5(현재 클러스터에서 사용버전)에서 java7을 통한 spark 데이터 처리 속도가 얼마나 나는지 궁금해졌다.


덤으로 scala spark이 동일한 데이터 처리 프로세스를 가지고 spark1.5, spark2.1.1버전에서 돌았을 때 성능도 궁금해져


간단히 70만 라인의 텍스트 파일로 파싱하고 필터링 처리를 하고 text파일과 orc파일로 변환해 적재하는 테스트를 진행하였다.


아직 scala를 spark2.1.1에서 테스트하는 부분은 확인하진 못했지만 확실히 spark2.1.1대 버전에서 java8 람다식을 활용해 처리하는 것


이 제일 빨랐다. 이부분은 좀더 테스트 후 포스팅 하도록 하겠다.


그리고 오전에는 딥러닝에 대한 세미나를 들었다. 세미나 발표를 통해 큰 깨달음이나 감명을 받진 못했지만


꾸준히 관심을 가지고 학습해 추후에 지금 처리하고 있는 데이터들에도 적용할 수 있는 방법을 연구해보면 좋을 것 같다.


아 그리고 틈틈히 scala공부도 하도록하자!


반응형
반응형

오늘 스파크 작업중 No TypeTag available for 에러가 발생하였다. 


밑에 소스코드 부분에서 val df = sQLContext.createDataFrmae(test_rdd3) 부분에서 발생하였고 


case class의 위치를 메소드의 바깥 부분으로 빼내어서 처리하였다. 


원인에 대해 참고할 만한 stackoverflow 내용이 있어 참고하였다.

https://stackoverflow.com/questions/29143756/scala-spark-app-with-no-typetag-available-error-in-def-main-style-app





[ 에러 발생 코드 ] 




[ 에러 해결 ]

case class를 main method 바깥으로 빼서 처리





뭔가 컴파일 시점에 case class를 정의하는 시점과 case class를 통한 spark의 action이 일어나는 시점과 연관이 있을 것 같

은데 자세한 원인에 대해서는 파악하지 못했다ㅠ 혹시 조언해주실분 있으면 감사하겠습니다. 

스칼라 공부를 좀 더 심도있게해야 할듯 싶다.


반응형
반응형

 



 자바스크립트를 처음 접하게 됬을 때 함수 표현식(밑에 설명)으로 선언된 함수를 보며 이건 뭐지? 하는 생각을 했었습니다. 자바스크립트는 함수를 정의하는 세 가지 방법이 있는데 이를 모르고 있다면 처음 접하셨을 때 많이 당황할 수 있습니다. 오늘은 자바스크립트에서 함수를 정의하는 방법과 함수를 호출하는 패턴 그리고 익명 함수에 대해 알아보도록 하겠습니다. 



1. 먼저 자바스크립트에서 함수란???

 자바스크립트에서 함수는 문장을 실행할 수 있는 고유한 스코프(scope)다. (scope에 대한 설명은 ver2 참고)

 자바스크립트에서 함수를 설명 할 때 "자바스크립트에서 함수는 first-class object(또는 citizen, value)다"는 정의를 알고 갈 필요가 있다. 대부분이 first-class object라는 단어에 대해 생소하실 텐데 여기서 말하는 first-class object는 다음과 같은 의미들을 포함합니다.


 1) first-class object는 변수에 저장할 수 있어야 한다.

 2) first-class object는 함수의 파라미터로 전달할 수 있어야 한다.

 3) first-class object는 함수의 반환값으로 사용할 수 있어야 한다.

 4) first-class object는 자료 구조에 저장할 수 있어야 한다.


 위와 같은 조건들을 충족시키는 객체를 first-class object라 하고 자바스크립트 함수를 의미합니다. 한 마디로 "자바스크립트에서 함수는 first-class object다"라고 생각하시면 될 것 같습니다. 이와 같이 자바스크립트에서 함수는 객체를 의미하고 함수는 변수, 배열, 객체에 저장될 수 있다는 뜻을 내포하고 있습니다. 또한 함수에 전달될 수도 함수에서 반환될 수도 있습니다. 



2. 함수를 정의하는 세 가지 방법  

  1 ) 함수 생성자 방식

 함수 생성자 방식은 함수 선언과 더불어 new 키워드를 통해 함수 객체를 생성하는 방법으로 마지막 매개변수는 함수의 로직(몸체 코드)부분을 의미하며, 그 외의 매개 변수는 인수가 됩니다.



 2 ) 함수 선언문 방식

 함수 선언문 방식은 우리가 주로 함수를 사용할 때 쓰는 방법으로 많이들 익숙하리라 생각 됩니다. 



 3 ) 함수 표현식 방식

 함수 표현식 방식은 변수를 선언하고 그 변수에 함수를 할당하고 있는 모습을 볼 수 있습니다. c나 c++, java와 같은 언어에서는 차마 볼 수 없는 광경입니다. 따라서 위의 함수를 선언하는 위의 세 가지 방법을 다 모르고 있을 경우 많이 당황하실 우려가 있습니다. 

저 코드를 실행하면 console.log를 통해 4, 4, 4가 찍히게 됩니다. 어떤 방식을 사용하든 문제는 없지만 함수 생성자 방식은 함수이 몸체 부분을 문자열로 작성해 주어야 되기 때문에 많이 불편하여 자주 사용되지 않는 편입니다. 



 3. 함수를 호출하는 네 가지 패턴

 함수는 다음과 같은 네 가지 시나리오나 패턴을 사용해 호출할 수 있습니다.

  1 ) 함수 패턴

 함수를 객체의 속성이 아닌 함수(fucntion)로서 호출할 때를 일컫는다.

 


  2 ) 메소드 패턴 

 함수를 객체의 속성(Property)에 저장하는 경우 이 함수를 메소드라고 부르고 이를 통해 함수를 호출하는 것을 메소드 패턴이라 한다. 


 3 ) 생성자 호출 패턴

 함수를 new라는 전치연산자와 함께 호출하는 것을 말한다. 생성자 호출 패턴을 사용하는 경우 호출한 함수의 prototype (자바스크립트에서 Function() 인스턴스를 만들 때 자바스크립트가 인스턴스에 부여하는, 이름이 "prototype"이고 기본값이 객체인 속성일 뿐이다. )속성의 값에 연결되는 (숨겨진)링크를 갖는 객체가 생성되고, 이 새로운 객체는 this에 바인딩된다.(자바스크립트의 prototype은 중요하므로 이에 대해서는 ver.4에서 포스팅하도록 하겠다) 


 console.log를 통해 찍히는 내용을 보자.




 4 ) apply()와 call() 패턴

 

 call()과 apply()의 차이점은 호출할 함수에 매개변수를 전달하는 방식이다. apply()는 배열방식으로 매개변수를 전달한다.



 4. 익명 함수

 익명 함수(anonymous function)란 이름이 없는 함수를 뜻한다. 익명 함수는 대부분 다른 함수에 매개변수로서 전달되는 경우가 많다.



 #다른 프로그래밍 언어와 달리 자바스크립트에서는 매개변수를 생략햐도 아무런 문제가 없다. 심지어 함수 선언 시 매개변수를 정의한 경우에도 문제가 없다. 전달하지 않은 인수에는 undefined 값이 저장된다. 물론, 인수를 전달하지 않으면 함수 내의 코드가 올바르게 동작하지 않을 수 있다.


 # 반대로 추가 매개변수(함수 선언 시 정의하지 않은 매개변수)를 함수에 전달해도 에러가 발생하지 않는다. 추가로 전달한 매개변수는 함수에 자동으로 추가되는 arguments 객체(함수로 전달된 매개변수를 저장하고 있는 배열 비슷한 객체)를 통해 접근할 수 있다.  



참조 

자바스크립트를 깨우치다 - 코디 린들리



 


반응형
반응형

 

 저번 포스팅에서 자바스크립트 언어의 특징을 시작으로 가장 기본적이면서도 중요한 내용들에 대해 알아보았다. (참고, [자바스크립트]자바스크립트 이것만은 꼭 알고가자(Part 1)) 이번 두번 째 자바스크립트 포스팅에서는 자바스크립트에서의 Scope와 Hoisting, Scope Chain, Closure에 대해 정리해보도록 하겠습니다.. 포스팅 내용중에 잘못된 부분이 있거나 개선할 점이 있다면 댓글로 의견 남겨주시면 감사하겠습니다.



1. 자바스크립트에서의 Scope는???

 스코프(Scope)란 범위를 뜻하는 단어로서 자바스크립트에서 변수의 종류에 따라 어느 범위까지 참조가 가능한지에 대한 의미쯤으로 생각하면 되겠다. 크게 전역 스코프(global scope), 지역 스코프(local scope, "함수 스코프"라고도 불림)로 구분된다. 



 1) 전역 스코프(global scope)란 말 그대로 global 영역에 선언된 전역변수가 스크립트 내의 모든 구간에서 사용될 수 있음을 의미한다. 밑의 그림을 보자.

 

 그림을 보면 먼저 글로벌 전역 변수를 선언한 것을 볼 수 있다. var global = 1로 설정한 값은 해당 스크립트의 어떤 영역에서도 사용이 가능하다. 물론 함수안에서도 전역변수를 사용할 수 있는 것을 예제를 통해 알 수 있다. console.log()로 값을 찍어 보면 선언하고 나서 찍었을 때와 함수에서 글로벌 전역변수를 리턴해주는 값 모두 처음 값을 지정해주었던 "1" 이 찍히는 것을 알 수 있다. (참고로 자바스크립트에서는 변수를 선언할 때 타입을 지정하지 않는다. 변수를 사용할 때 무슨 타입이든 var를 사용한다. 또한 변수를 선언할 때 'var'를 입력하지 않으면 전역변수로 인식하기 때문에 전역변수든 지역변수든 모두 'var'를 붙여 일관성을 부여하도록 하자. 밑의 '5)'설명 참고) 





 2) 지역 스코프(local scope, "함수스코프")란 쉽게 말해 해당 함수안에서만 접근가능한 private variable을의미한다. 즉 함수 내에서 var를 사용해 정의된 코드는 지역 스코프에서만 유효하고 해당 함수 내에서 정의된 중첩 또는 자식 함수를 비롯해 해당 함수 내부에서만 사용 가능하다. 

 

 그림을 보면 test()함수안에서 선언된 'local'이라는 지역변수는 함수 외부 {} 밖에서는 그 변수의 유효범위가 끝나버리기 때문에 접근할 수 없는 것을 볼 수 있다. 





 3) 전역변수와 지역변수를 동일한 이름으로 사용하게 되면 어떻게 될까???

 그럼 만약에 전역변수와 지역변수를 동일한 이름으로 사용했을 경우 어떤 문제가 발생할 수 있을까? 자바스크립트에서는 전역 변수 영역에 선언된 변수와 동일한 이름의 지역변수를 사용할 수 있다. 예를 보자.

 

 그림에서 보면 전역변수와 지역변수를 동일한 이름으로 사용을 했을 경우에도 전혀 문제가 되지 않는 것을 볼 수 있다. 보면 test()함수를 실행해 변수의 값을 찍어보면 지역변수의 값(3)이 찍히고 그냥 "global"변수 값을 찍어보면 전역변수의 값인 '1'이 찍히는 것을 확인할 수 있다. 다시말해 전역변수와 지역변수를 동일한 이름으로 사용하여도 각기 다른 변수객체가 만들어 진다는 것을 알 수 있다. 이 부분에 대해서는 밑의 설명들을 참고하길 바란다. (또한 혼란을 막기 위해 이렇게 중첩된 변수 네이밍 사용을 가급적 사용하지 않는 것이 좋다.)





 4) 자바스크립트에는 블록 스코프가 없다. 

 자바스크립트에서는 조건문 ( if() { } )과 반복문( for(){} )은 스코프를 만들지 않으므로 조건문과 반복문 사이에도 변수를 서로 재정의할 수 있다. 

 

 그림에서와 같이 자바스크립트에는 블록 스코프가 없기 때문에 no의 값이 for문에서 바뀌는 것을 확인하였다. 자바스크립트에는 함수, 전역, eval() 스코프만 있음을 명심하자.





 5) 함수 내에서 변수 선언 시 var를 사용해 스코프에서 발생할 수 있는 문제를 피하자.

 위에서 잠깐 설명했다 시피 자바스크립트는 변수를 선언할 때 따로 타입을 지정하지 않고 var를 사용해 선언하게 된다. var 키워드 없이도 변수를 선언할 수 있는데 이는 함수 안에서 선언한다 하더라도 전역 변수의 스코프를 갖게 된다. 

 

 그림과 같이 첫 번째는 test()함수 안에 var를 사용해 지역변수로 선언하고 함수 범위 밖에서 'boo' 지역변수에 접근했을 때는 접근할 수 없지만 두 번째에서는 var 키워드를 사용하지 않고 'boo'를 선언하였기 때문에 전역변수로 인삭하게 되고 test()함수 밖에서도 접근할 수 있게 된다. 따라서 함수 내에서 변수를 선언할 때에는 항상 var를 사용하도록 하자. 그렇지 않으면 스코프 때문에 혼란스러워지는 문제가 발생할 수 있기 때문이다. 





2. 자바스크립트 Hoisting 이란???

 'hoist = 끌어올리다' 라는 뜻으로 자바스크립트에서는 변수 선언과 함수 선언은 해당 유효범위의 가장 최상위로 끌어 올려짐을 의미합니다. 예제를 통해 좀 더 쉽게 살펴보도록 하겠습니다. 

 

 그림을 보게 되면 처음 console.log에서는 undefined를 찍어내는 것을 파악할 수 있습니다. 이와 같은 이유는 자바스크립트 엔진에 의해 아래와 같이 해석되기 때문입니다.

 

 이렇게 'name' 변수의 선언부만 호이스팅 되기 때문에 발생합니다. 자바스크립트의 호이스팅은 함수나 변수의 선언부만 최상위로 끌어올리게 되고 초기화과정은 기존의 위치에서 실행되게 됩니다. 다시 말해 변수의 선언이 초기화나 할당시에 발생하는 것이 아니고, 유효범위의 최상위로 호이스트 되는 것입니다. 유효 범위 안에서 변수에 할당한 값을 활용하고 싶을 때에는 항상 유효범위의 최상위에 선안하고 값을 초기화 해주도록 하는 것이 자바스크립트의 호이스팅기능으로 인해 발생할 수 있는 문제들을 조금이나마 줄여줄 것 입니다.





 3. 자바스크립트의 Scope chain

 자바스크립트는 변수를 찾을 때 스코프의 계층 구조에 기반한 검색 체인을 거슬러 올라가며 추적하게 됩니다. 예제를 통해 좀 더 쉽게 살펴보도록 하겠습니다.

 

 그림에서 보면 console.log를 통해 "scopeChain"을 찍어 내는 모습을 볼 수 있습니다. console.log를 func2 스코프에 쓰여있지만 실제로 자바스크립트 scope chain을 통해 전역 스코프의 scopeChain 변수에 접근에 값을 출력하게 됩니다. func2 함수 스코프 내에 포함되어 있지 않은 scopeChain 값을 찾는 과정은 먼저 func2 함수에서 scopeChain 라는 변수를 찾게 되고, 이 값이 없으면 func2 의 부모 함수인 func1에서 검색을 하게 되고 여기에도 없으면 func1 의 부모 함수가 없기 때문에 전역 스코프에서 값을 찾게 됩니다. 전역 스코프에서 scopeChain을 발견하게 되면 이 값을 func2로 전달하게 되는 것을 자바스크립트의 scopeChain의 핵심 역할 입니다. 만약 전역 스코프에도 해당 내용이 정의되어 있지 않았다면 자바스크립트는 undefinded를 반환하게 됩니다. 



명확한 이해를 위해 예제를 하나 더 살펴보도록 하겠습니다.

 

 그림에서 보듯이 console.log는 func2에서 수행되고 있으면 "number1 + number2 + number3"의 연산을 수행하게 됩니다. 각각의 변수들은 각기 다른 스코프에서 선언이 되었습니다. 자바스크립트는 scope chain을 통해 해당 변수들을 찾게 되고 number3, number2, number1의 순서로 chain을 통해 접근하여 값을 func2 함수로 전달하여 연산을 수행하게 됩니다. 이렇듯 func2 함수에서 참조한 변수는 지역 스코프에 없을 경우 스코프 체인에서 변수를 검색하게 되며 스코프 체인을 검색할 때는 가장 처음 발견한 값을 반한하게 됩니다. (예를 들어 위에 number1, number2 의 명칭을 number3으로 변경해 주게 되면 console.log에는 9가 찍히게 됩니다.)


 이렇듯 스코프 체인을 검색할 때는 가장 처음 발견한 값을 반환하게 되므로 상위 범위에 대해서는 검색을 하지 않고 연산을 수행하여 9가 찍히게 됩니다. 



###스코프 체인은 함수를 실행한 위치가 아닌 정의한 위치에 의해 결정되어 집니다. 이를 가리켜 문법적 스코핑(lexical scoping)이라고도 합니다. 스코프 체인은 함수를 호출하기 전에 이미 만들어지며, 이 덕분에 우리는 클로저(closure)를 만들 수 있게 됩니다. 





 4. 자바스크립트 Closure

 

 Closure는 scope chain과 매우 밀접하게 연관되어 있기 때문에 scope chain의 이해가 우선시 됩니다. 그림에서 보면 sequencer 내부 함수에 ++seq를 반환하고 있는 것을 볼 수 있습니다. 이는 일반적으로 다른 언어에서는 유효범위를 벗어난 쓸 수 없는 변수이지만 자바스크립트에서는 scope chain을 통해서 연결이 가능하게 됩니다. 내부 함수는 자신이 선언된 환경에 대한 연결을 갖게 됩니다. 다시 말해 foo() 함수가 클로져를 갖게 됩니다. 클로져는 두개의 것으로 이루어진 특별한 오브젝트로 첫 번째는 함수, 두 번째는 그 함수가 만들어진 환경을 가지게 됩니다. 그 함수가 만들어진 환경은 함수가 만들어질 때 사용할 수 있었던 변수들로 이루어지고 이 경우에 foo()함수는 sequencer의 내부 함수와 seq 변수를 포함하는 클로져가 됩니다. 





[글을 쓰며]  

 자바스크립트 이것만은 알고가자 (Ver 2)를 포스팅하면서 어떻게 하면 좀 더 다른 누군가가 내 글을 봤을 때 '해당 내용들에 대해 쉽게 이해할 수 있을까'라는 고민을 많이 하게 됬다. 그로 인해 깨달은 것은 내가 그 내용에 대해 완벽히 파악하고 있지 못하다면 쉽게 설명하기 힘들다는 것과 내가 이해하는 내용을 글로 쉽게 옮겨 내는 것 또한 많은 노력이 필요하다는 것이다. 앞으로 글을 쓸 때 앞의 2가지 깨달음을 잊지 않고 포스팅을 해나가도록 하겠다. 



[참조]

자바스크립트를 깨우치다 - 코디 린들리 지음










반응형
반응형

회사에 들어와 처음 웹프로그래밍을 접하면서 자바스크립트에 대한 지식이 전무한 상태에서 무작정 남들이 작성한 코드를 토대로 감으로 프로그래밍을 했었다. 그 당시는 교육이수 중이라서 프로젝트 개발 시간도 부족한 나머지 따로 자바스크립트를 공부할 시간을 갖지 못했었다. 그래서였는지 조그마한 프론트 기능을 추가했을 때 사소한 문제들에 자주 부딪혔던 기억이 있다. 아직도 자바스크립트 공부가 많이 필요하지만 그 중 사소한 실수를 줄여 소중한 시간을 아낄 수 있는 기초 문법들에 대해 알고 넘어가 보려 한다.

 자바스크립트??? 객체기반언어, 인터프린터 언어 자바스크립트는 브라우저 기반에서 실행되는 객체 기반 언어이다. 또한 인터프린터 언어로 컴파일 언어와는 반대로 컴파일 과정이 생략되고 실행 중에 바로 한줄 한줄 번역 해 가며 실행된다. 이렇듯 한줄 한줄 변환되기 때문에 컴파일 언어보다 실행 속도가 당연히 떨어지게 된다. 또한 디버깅 혹은 에러를 잡아 내기가 컴파일 언어보다 힘들다. 하지만 인터프리트 언어는 장점 또한 가지고 있는데 한줄 한줄 해석되는 언어이다보니 자신의 프로그램을 수정하거나 보완한 경우, 전체를 완선히 새로 'Recompile'할 필요가 없어 코드를 수정하고 실행해 즉각 테스트가 가능해진다. (작업중인 jsp파일의 소스코드를 수정하고 웹페이지를 통해 즉시 확인해 볼 수 있는 이유) 또한 웹 브라우저의 Script 엔진이 직접 코드를 해석하여 처리하므로 적은 시스템 부하와 환경에 독립적인 장점을 가지고 있다.

 자바스크립트의 특징은???첫번 째, 자바스크립트는 객체 기반 언어로서 상속과 클래스가 존재하지 않는다.두번 째, 자바스크립트는 인터프리터 언어로서 클라이언트 웹 브라우저에 의해 해석되고 실행된다.세번 째, JavaScript는 HTML 문서 내에 기술되고 HTML 문서와 함께 수행된다.네번 쨰, JavaScript는 HTML에 연산, 제어 등 프로그래밍적인 요소를 추가하고, 클라이언트의 자원을 활용할 수 있게 한다.


 HTML에서 자바스크립트의 위치는??? <head>??<body>??? 보통 JSP에서 스크립트의 파일을 <head>에 모아두는데 학습을 하다 보니 head에 모아두는 것이 좋지 않다는 걸 알게 되었다. 보통 브라우저는 HTML 태그를 위부터 아래로 순서대로 읽어가며 DOM Tree를 만들고 바로바로 화면에 렌더링을 한다. 그런데 도중에 <script>태그를 만나면 렌더링을 일단 중지하고 스크립트를 실행하고 나서 다시 렌더링을 시작하게 된다. 문제는 여기서 발생한다. 만약 선언되어 있는 스크립트 중에 실행하는데 오래걸리는 스크립트가 있을 경우 화면 렌더링은 그 시점에서 멈추게 되는데 이로인해 사용자는 제대로 로딩되지 않은 공백 화면을 오래 마주하게 되는 문제가 생길 수 있다. (이로인해 많은 사용자들이 뒤로가기 버튼을 누르거나 다른 페이지로 넘거가게 된다) 하지만 스크립트를 <body> 가 닫히기 전에 넣어주게 되면 이러한 문제를 해결할 수 있다.</body>바로 직전이나 </html>후에 스크립트를 넣어주게 되면 DOM이 다 로딩되고 수행되기 때문에 복잡한 로직 수행이 수반된 스크립트나 이벤트 처리들을 다수 포함하고 있는 스크립트는 <body>가 닫히기 전에 명시해 주는 것이 좋다. 하지만 <body>사이에서 <script>를 찾는 것이 번거롭거나 불편하다고 느낄경우 처음 head에 스크립트를 선언시 defer기능을 통해 문서가 다 로딩 된 후 스크립트를 읽도록 하는 기능도 지원하는 것으로 알고 있다.(추가적인 부분은 구굴에 찾아보길 바란다)


 자바스크립트에서 기본 타입은??? 자바스크립트에서는 크게 Number, String, Boolean, Object, Null, Undefined의 타입이 존재한다. Object타입안에는 Function, Array, Date, RegExp(정규식)이 존재한다. 자바스크립트에서 사용되는 대부분의 데이터 타입은 객체로 존재하며 그에 따른 사용 또한 객체 기반이 될 수 밖에 없다.


 자바스크립트에서 Nan은 무엇인가??? 자브스크립트를 짜다가 Nan이라는 단어를 접하고 이게 뭐지 했던 때가 있었다. Nan은 Not a Number의 약자로 말그대로 해당 하는 값이 숫자가 아니라는 뜻이다. 자바스크립트에서 해당 데이터가 NaN인지 검사해주는 isNaN()이라는 내장 객체가 존재하는데 isNaN()은 NaN인지 여부를 검사하는 함수임으로 NaN일 때 true를 반환한다.


 자바스크립트에서 Null과 Undefined의 차이는???자바스크립트를 작성하다 보면 Undefined를 자주 접하게 될 것이다. 처음 Undefined를 접하게 되면 Null과 같은건가 하는 생각을 하게 되는데 둘은 다르다는 것을 알고 있어야 한다. 이 둘에 대한 차이를 정확히 이해하지 않고 스크립트를 작성하게 될 경우 사소한 부분에서 에러와 함께 시간을 많이 빼앗기게 될 것이다. 자바스크립트에서 null은 값이 없음을 나타내고 Undefined는 초기화(선언) 되지 않았거나 값이 할당되지 않았음을 나타낸다. Null은 개발자가 의도적으로 비어있는 값을 부여한 것이고 Undefined는 애당초 어떠한 값도 할당 되지 않은 것이다. 자바스크립트는 변수의 선언과 초기화를 동시에 하지 않아도 되는데 선언만 하고 초기화 되지 않은 변수는 초기화되지 않았거나 값이 할당되지 않았음을 표현하는 undefined라는 값을 할당받게 된다. 정리하자면 NULL은 변수가 참조하는 객체가 없음(null)을 나타내고 Undefined는 그 변수가 참조하는 객체를 아직 지정하지 않음(not Initialized)을 뜻하고 Undefined값을 가지는 변수는 할당을 통해 값을 가지고 이 값을 해제할 때 null타입이 되는 것이다.


자바스크립트에서 ===???프로그래밍을 하면서 '=='는 많이 접해보았을 것이다. 무엇을 비교할 때 많이 사용하는데 자바스크립트에서 멋도 모르고 '=='를 다른 언어에서 쓰던것 처럼 쓰게되면 큰코 다치는 날이 올 것이다.간단히 설명하자면 ==는 값만으로 체크를 하는 것이도 ===은 변수의 타입과 값을 모두 체크하여 비교하는 것이다.ex) x=3이라고 가정x==5 (false)x==3 (true)

x==="3" (false)x===3 true)가 되게 된다. 그럼 x=="3"을 하게 되면 결과는 어떻게 될까??? 상식대로라면 false를 뱉어야 하지만 true가 되게 되는데 자바스크립트의 ==는 형변환은 시도해 비교하게 되기 때문에 이와 같은 상황이 발생한다. 따라서 무작정 ==와 ===를 사용하게 되면 나중에 큰 문제에 직면하게 될 것이다. 반드시 차이를 정확히 이해하고 사용하기 바랍니다.


⊙ 자바크립트를 공부하는 입장으로서 가장 기본적인 내용에 대해 알아보았다. 다음 포스팅 '자바스크립트 이것만은 알고가자(Ver. 2)'에서는 자바스크립트에서의 Scope, Hoisting, Scope Chain, Closure에 대해서 알아보도록 하겠습니다.





반응형
반응형

데이터 엔지니어로 살아가기 143일째(커스텀타겟팅) - 0721금요일


광고주 태그매니저에서 들어오는 데이터들을 orc로 적재하는 작업을 마무리하였다.


camus를 통해 kafka에서 데이터를 가져와 매시간 데이터를 적재하고 있지만


커스텀타겟팅에 사용하기에는 부적합하다는 판단에 orc로 적재하기로 결정하였다.



작업을 완료하기까지 많은 수행착오를 겪었다. 인입되는 로그에서 실제 bid별 관심사를


추출해 적재하기로 사전에 얘기가 되었지만 실제로 작업을 완료하고 확인해보니 


생각보다 관심사를 추출하는 부분에서 처리시간이 많이 소모되었다. 


관심사 추출 후 date, action별로 partitioning하여 적재하는 시간이 단순 컬럼으로만 분리해서


적재했을 때의 시간보다 15배정도의 시간이 더 걸렸다.t.t

 


결국에는 일단 orc로 적재한 후 관심사 데이터가 필요할 경우 bid별 관심사 추출데이터와


join해서 사용하는 편이 리소스 활용측면이나 확장성 측면에서 더 효율적이겠다는 결정을 내렸고 


scala spark으로 다시 orc 적재하도록 마무리하였다.



orc적재 작업을 진행하면서 java-spark에 어느정도 더 익숙해졌고 관심사 추출로직에 대해


심도있게 파악할 수 있었다는 점에서 삽질도 많이했지만 좋은 기회가 되었던 것 같다.


이제 실제 커스텀타겟팅 메인 프로젝트 작업에 슬슬 시동을 걸어봐야겠다~


아! 그리고 틈틈히 scala공부를 하도록하자~scala 와 spark는 뗄래야 뗄 수 없는 관계

반응형
반응형

최근 작업중 unix date를 파싱해야는 경우가 있어서 아무렇지 않게


String unixDate = "1498906817.357"

String[] parseDate = unixDate.split(".");

String parsedDate = Long.parseLong(parseDate[0]);


다음과 같이 썼는데 파싱된 데이터에 값이 안들어있다는...


확인해보니 split의 인자로 들어가는  .(dot)이 정규식이기 때문이었다. 

정규식에서는 .(dot)은 무작위의 한글자를 의미하므로 모든 문자가 토큰이 되기 때문에 배열에 남는게 없게 되는 것이다.

그렇기 때문에 이를 피하기 위해서는 이스케이프(\\)를 문자앞에 써줘야 한다.



String unixDate = "1498906817.357"

String[] parseDate = unixDate.split("\\.");

String parsedDate = Long.parseLong(parseDate[0]);


뭔가 split 메서드를 사용해 parsing을 했는데 값이 정상적으로 나오지 않는다면 정규식을 의심하자.



[ 참고 ]

there are 12 characters with special meanings: the backslash \, the caret ^, the dollar sign $, the period or dot ., the vertical bar or pipe symbol |, the question mark ?, the asterisk or star *, the plus sign +, the opening parenthesis (, the closing parenthesis ), and the opening square bracket [, the opening curly brace {, These special characters are often called "metacharacters".

반응형

+ Recent posts