'개발관련'에 해당되는 글 51건
- 2015.11.17 :: mongoDB crud(1)
- 2015.11.09 :: SpringMVC+Memcached(4)
- 2015.11.09 :: springmvc+memcacehd(3)
- 2015.11.09 :: SpringMVC + memcached maven 및 bean 설정 (2)
- 2015.11.06 :: SpringMVC + memcached(1)
- 2015.10.30 :: lucene 기초 - index
- 2015.10.30 :: lucene 기초
- 2015.10.30 :: mongodb 의 update, delete
- 2015.10.30 :: mongDB create table 및 색인 생성
- 2015.10.30 :: Mongo 단일 서버 설정
1 2 3 4 5 6 7 8 9 10 11 12 13 | use test db.crudtest.insert( { "idx" : 1, "name" : "aaa", "id" : "aaa", "type" : { "test1" :"test1", "test2" :"test2" } } ); | cs |
몽고 db는 내부에 js로 동작(?)하는 듯한 느낌이다.
먼저 rdb 처럼 어떤 db를 사용할지를 선택한다. rdb처럼 먼저 스키마를 생성하고 이런짓은 안하고 없으면 만들고 있으면 그냥 가져다 쓴다. 머 여타 nosql도 마찬가지지만.
use test를 하면 (여기서 ; 세미콜론을 붙으면 안되더라구요 =_=;) db라는 객체에 저장이 되는듯하다.
이후 db.(콜렉션이름).insert 후 저장할 값을 json형태로 저장하면 된다.
콜렉션은 document 기반의 table을 뜻한다. 머 elasticsearch나 solr, lucene등 document기반이다.
insert형식은 자유롭다. object 를 기본으로 하며, 각 키값(field) : value 여기서 value는 다시 object또는 array가 올수 있다.
1 2 3 4 5 6 7 8 9 | db.crudtest.insert( { "idx" : 3, "name" : "gno", "id" : "gno" } ) | cs |
다음은 update문이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | //update db.crudtest.update( //where { "name" :"ryu" }, { //set $set:{"name":"gun-ho"} , //add $set: { "language": ["java","js","angular"] }, //field delete $unset : { "id" : 1 } } ) | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | db.crudtest.update( { "name" :"gun-ho" }, { $push : { "language" : "c++" } } ); db.crudtest.update( { "name" :"gun-ho" }, { $push : { "language" : { $each : ["c","python"] } } } ); | cs |
1 2 | db.crudtest.remove() | cs |
3번과 dto는 동일하다.
하지만 bean은 변경이 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <aop:aspectj-autoproxy /> <!-- 이부분은 아마도 버그인듯 문서에는 없었는데 안쓰면 에러가 난다. --> <import resource="simplesm-context.xml" /> <bean name="defaultMemcachedClient" class="com.google.code.ssm.CacheFactory"> <property name="cacheClientFactory"> <bean name="cacheClientFactory" class="com.google.code.ssm.providers.xmemcached.MemcacheClientFactoryImpl" /> </property> <property name="addressProvider"> <bean class="com.google.code.ssm.config.DefaultAddressProvider"> <property name="address" value="192.168.0.105:11211" /> </bean> </property> <property name="configuration"> <bean class="com.google.code.ssm.providers.CacheConfiguration"> <property name="consistentHashing" value="true" /> </bean> </property> </bean> <bean class="com.google.code.ssm.Settings"> <property name="order" value="500" /> </bean> | cs |
service는 다음과 같이 설정하면 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | @Override @CacheEvict(value="cachable") public boolean delete( long idx) { userDao.delete(idx); return false; } @Override @CachePut(value="cachable", key="#userDTO.idx") public UserDTO write( UserDTO userDTO) { return userDao.save(userDTO); } @Override @Cacheable(value="cachable", key="#idx") public UserDTO read( long idx) { UserDTO userDTO = userDao.findOne(idx); // userDao.save(userDTO); return userDTO; } | cs |
기존 ehcached와 동일하다. number 계열도 된다.
아마도 난 이 방법으로 사용할 듯 보인다.
소스 주소는 https://github.com/zest133/Memcached.git 여기로..
먼저 dto 설정.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | @Entity @Table(name="user") //중요!!!!!!!!!!!!!!!!!! memcached 할때!!!! public class UserDTO implements Serializable{ @Id private long idx; @Column(unique=true,nullable=false) private String id; @Column(nullable=false) private String pwd; private String email; @Column(nullable=false) private String name; public UserDTO(){ } public UserDTO(long idx, String id, String pwd, String email, String name){ this.idx = idx; this.id = id; this.pwd = pwd; this.email = email; this.name = name; } public long getIdx() { return idx; } public void setIdx(long idx) { this.idx = idx; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getName() { return name; } public void setName(String name) { this.name = name; } } | cs |
기본적인 user table로서 jpa 관련 annotation 으로 셋팅. 중요한 점은 memcached는 Serializable를 해야한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ..... 생략......... @Override @InvalidateSingleCache(namespace = "CacheKeyMethod") public boolean delete(@ParameterValueKeyProvider long idx) { userDao.delete(idx); return false; } @Override @UpdateSingleCache(namespace = "CacheKeyMethod", expiration = 3600) public UserDTO edit( @ParameterValueKeyProvider @ParameterDataUpdateContent UserDTO userDTO) { return userDao.save(userDTO); } @Override @ReadThroughSingleCache(namespace = "CacheKeyMethod", expiration = 3600) public UserDTO read(@ParameterValueKeyProvider long idx) { UserDTO userDTO = userDao.findOne(idx); // userDao.save(userDTO); return userDTO; } ..... 생략......... | cs |
1 2 3 4 5 6 | @CacheKeyMethod public String getId() { return id; } | cs |
사용 환경은 다음과 같다.
springMVC 3.2, hsqldb, jpa, hibernate, xmemcached-provider, spymemcached-provider ,com.google.code.simple-spring-memcached 이렇게 메이븐에 defendancy를 추가한다.
먼저 @UpdateSingleCache 이런 식으로 사용하는 방법을 먼저 설명한다. maven 설정 자체는 두 가지 방식다 동일하다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${org.springframework-version}</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>1.1.0.RELEASE</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>4.3.8.Final</version> </dependency> <dependency> <groupId>com.google.code.simple-spring-memcached</groupId> <artifactId>xmemcached-provider</artifactId> <version>3.6.0</version> </dependency> <dependency> <groupId>com.google.code.simple-spring-memcached</groupId> <artifactId>spymemcached-provider</artifactId> <version>3.6.0</version> </dependency> <dependency> <groupId> com.google.code.simple-spring-memcached </groupId> <artifactId>spring-cache</artifactId> <version>3.6.0</version> </dependency> | cs |
bean 등록은 다음과 같이 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <!-- spring data jpa 설정 --> <!-- jpa repository가 위치한 패키지 경로 등록 --> <jpa:repositories base-package="com.zest.memcached.user.dao" entity-manager-factory-ref="entityManagerFactory" /> <!-- 하이버네이트의 SessionFactory 에 상응하는 jpa의 EntityManagerFactory 등록 --> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" /> </property> <property name="dataSource" ref="dataSource" /> <property name="jpaProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop> <!-- Hsql 형식에 맞게 변환해주는 클래스 --> <prop key="hibernate.connection.pool_size">1</prop> <prop key="hibernate.connection.shutdown">true</prop> <!-- hsql에 있는 마지막 연결이 끊어지면 데이터베이스 shutdown 하는 플래그 --> <prop key="hibernate.show_sql">true</prop> <!-- SQL 출력 --> <prop key="hibernate.hbm2ddl.auto">create</prop> <!-- 테이블 자동 생성 --> </props> </property> <!-- 엔티티 정의된 클래스들이 있는 패키지 등록 --> <property name="packagesToScan" value="com.zest.memcached.user.dto" /> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"></property> </bean> <!-- spring data jpa 설정 끝 --> | cs |
위 설명은 jpa 설정 부분이다.
xmemcached 설정은 다음과 같다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <aop:aspectj-autoproxy /> <!-- aop 관련 설정 --> <import resource="simplesm-context.xml" /> <bean name="defaultMemcachedClient" class="com.google.code.ssm.CacheFactory"> <property name="cacheClientFactory"> <bean name="cacheClientFactory" class="com.google.code.ssm.providers.xmemcached.MemcacheClientFactoryImpl" /> </property> <property name="addressProvider"> <bean class="com.google.code.ssm.config.DefaultAddressProvider"> <property name="address" value="192.168.0.105:11211" /> </bean> </property> <property name="configuration"> <bean class="com.google.code.ssm.providers.CacheConfiguration"> <property name="consistentHashing" value="true" /> </bean> </property> </bean> <bean class="com.google.code.ssm.Settings"> <property name="order" value="500" /> </bean> | cs |
코드 부분은 다음에............
멤 캐쉬는 글로벌 캐쉬로 아마도 redis(아직 공부중) 보다 사용이 쉽다. Spring에선 ehcache를 지원하지만 local 캐쉬인 관계로
정리 할려고 한다.
출처 : http://wiki.gurubee.net/pages/viewpage.action?pageId=26740267
memcached는 위의 그림으로 설명이 된다. 머 그 이상 이하도 없다.
redis와 다른점을 말하자면, redis는 nosql 메모리 db로 in-memory 기반 으로 사용 될 수도 있고, 캐쉬로 사용 될 수 있으며, 이를 다시 clustering을 사용 할 수 있다.
여튼 memcached는 사용이 간단하므로, 널리 쓰인다. 설치는 위 그림 출처에 가보면 사용이 가능하다.
memcached 명령어는 http://smallmir.tistory.com/173 참조 하면 된다.
memcached는 많은 언어를 지원하며, java도 그중에 하나이다. 스프링에서는 xmemcached 라이브러리와 spymemcached 라이브러리 두개가 존재한다.
아무거나 써도 상관없을듯.....
사용법은 두가지로 나뉘는 듯 보이는데 @UpdateSingleCache 이런 annotation을 쓰는 방법과 기존 ehcache 와 동일한 방법 두가지로 나뉜다.
이번 글에선 색인에 대해 알아보자.
색인은 I am a boy. 라는 단어가 있으면 특정 분석기(analyzer)를 통해 분석이 되며 이 분석된 단어(Term)들이 색인 되어 진다. lucene은 rdb와 틀리게 증분색인으로 이루어져 있다.
WhiteSpaceAnalyzer 를 사용하면 위 문장은 I, Am, A, Boy로 분석이 된다.
StandardAnalyzer는 Boy 정도만 나올 것이다. 이유는 내부적으로 Stopword를 가지고있다.
결국 StandardAnalyzer는 WhiteSpaceTokenizer+StopFilter+lowercaseTokenizer 정도로 구성된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | @ContextConfiguration(locations={ "file:src/main/webapp/WEB-INF/spring/root-context.xml"}) @RunWith(SpringJUnit4ClassRunner.class) public class TestHtmlIndexer { private static final Logger logger = LoggerFactory.getLogger(TestHtmlIndexer.class); private Directory dir = null; // @Autowired // private WhitespaceAnalyzer whitespaceAnalyer; @Autowired private StandardAnalyzer standardAynalyzer; private CustomSimpleAnalyzer customAnalyzer; private WhitespaceAnalyzer whitespaceAnalyzer; private SimpleAnalyzer simpleAnalyzer; private IndexWriter writer; @Autowired private HtmlWithTikaParser htmlParser; @Autowired private TieredMergePolicy tmp; @Value("${fileindex}") private String path; @Before public void setup() throws IOException, InterruptedException{ customAnalyzer = new CustomSimpleAnalyzer(Version.LUCENE_36); //저장 방식에는 많이쓰는 방식이 몇 가지를 지원하는데, NIODirctory, SimpleDirectory,FSDirectory, RAMDictory등 //RAMDirtory - 메모리에 index를 저장 테스트시 많이 사용. //NIODirectory - unix계열에서만 가능 하지만 버그가 있는것으로 알고있음. //FSDirectory - 이걸 가장 많이 쓴다고 함. //디렉토리를 open dir = FSDirectory.open(new File(path)); //어떤 색인으로 할것인지 대한 설정. IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_36, customAnalyzer); //색인은 어떤 형태로 저장할지 에 대한 셋팅. //OpenMode.CREATE - 색인시마다 기존 색인 삭제 후 재 색인 //OpenMode.CREATE_OR_APPEND - 기존 색인이 없으면 만들고, 있으면 append 함. //OpenMode.APPEND - 기존 색인에 추가. iwc.setOpenMode(OpenMode.CREATE_OR_APPEND); //색인 파일의 병합 전략인데 사실 읽어봐도 이해를 못해서 걍 씀. iwc.setMergePolicy(tmp); //lucene은 rdb와 다르게 lock에 대한 처리를 안해준다. 단지, index시 lock 파일이 존재하면 error가 발생한다. //이 때문에 필히 lock 체크를 해줘야함. lockChecker(); //드디어 indexwrite 생성. 디렉토리와 config를 매개변수로.... writer = new IndexWriter(dir, iwc); } public void lockChecker() throws IOException, InterruptedException { //IndexWriter.WRITE_LOCK_NAME - 실제 index 시 directory에 보면 xxx.lock 파일이 존재하게 되는데 //존재 할 경우는 lock으로 판단. while(dir.fileExists(IndexWriter.WRITE_LOCK_NAME)){ // dir.clearLock(name); Thread.sleep(10); } } public void addDocument(HtmlDTO dto){ try { writer.addDocument(dto.convetDocument()); } catch (CorruptIndexException e) { // TODO Auto-generated catch block logger.error(e.getMessage()); } catch (IOException e) { // TODO Auto-generated catch block logger.error(e.getMessage()); } } public void writeClose() throws CorruptIndexException, IOException{ if(writer != null){ writer.close(); } } @Test public void testAddDocument() throws CorruptIndexException, IOException, SAXException, TikaException{ URL url = this.getClass().getClassLoader().getResource("html/xxx.json"); String path = url.getPath(); File file = new File(path); JSONParser parser = new JSONParser(); try { Object obj = parser.parse(new FileReader(path)); JSONObject jsonObject = (JSONObject) obj; Iterator<String> keys = jsonObject.keySet().iterator(); while(keys.hasNext()){ String key = keys.next(); JSONObject valueObj = (JSONObject) jsonObject.get(key); String filepath = valueObj.get("FilePath").toString(); String CATEGORY_TEXT_ID = valueObj.get("CATEGORY_TEXT_ID").toString(); String breadcrumb = valueObj.get("Breadcrumb").toString(); String CATEGORY_TREE = valueObj.get("CATEGORY_TREE").toString(); String CATEGORY_ID = valueObj.get("CATEGORY_ID").toString(); String LOCALE_KEY = valueObj.get("LOCALE_KEY").toString(); String CATEGORY_TITLE = valueObj.get("CATEGORY_TITLE").toString(); String CATEGORY_DESC = valueObj.get("CATEGORY_DESC").toString(); HtmlDTO dto = new HtmlDTO(); dto.setCategoryTextId(Integer.parseInt(CATEGORY_TEXT_ID)); dto.setCategoryTree(CATEGORY_TREE); dto.setBreadcrumb(breadcrumb); dto.setCategoryId(Integer.parseInt(CATEGORY_ID)); dto.setLocaleKey(LOCALE_KEY); dto.setCategoryTitle(CATEGORY_TITLE); dto.setCategoryDesc(CATEGORY_DESC); url = this.getClass().getClassLoader().getResource("html/"+filepath); // 이부분 수정. ArrayList<String> list = htmlParser.htmlParser(url.getPath()); dto.setText(list.get(0)); dto.setHtml(list.get(1)); addDocument(dto); } } catch (FileNotFoundException e) { logger.error(e.getMessage()); } catch (IOException e) { logger.error(e.getMessage()); } catch (ParseException e) { logger.error(e.getMessage()); } } @After public void tearDown() throws CorruptIndexException, IOException{ writeClose(); } } | cs |
위 예제는 json을 읽어서 특정 경로에 있는 html을 색인하는 과정을 junit으로 해본것이다.
convertDocument() 는 다음과 같다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ..생략........ public Document convetDocument() { // TODO Auto-generated method stub Document doc = new Document(); NumericField categoryTextIndex = new NumericField("categoryTextId",Field.Store.YES,true); categoryTextIndex.setIntValue(this.getCategoryTextId()); doc.add(categoryTextIndex); // NumericField categoryId = new NumericField("categoryId",Field.Store.YES,true); categoryId.setIntValue(this.getCategoryId()); doc.add(categoryId); doc.add(new Field("categoryTree",this.getCategoryTree(),Field.Store.YES,Field.Index.NOT_ANALYZED )); doc.add(new Field("localeKey",this.getLocaleKey(),Field.Store.YES,Field.Index.NOT_ANALYZED )); doc.add(new Field("breadcrumb",this.getBreadcrumb(),Field.Store.YES,Field.Index.NOT_ANALYZED )); doc.add(new Field("categoryTitle",this.getCategoryTitle(),Field.Store.YES,Field.Index.NOT_ANALYZED )); doc.add(new Field("categoryDesc",this.getCategoryDesc(),Field.Store.YES,Field.Index.NOT_ANALYZED )); doc.add(new Field("text", this.getText(), Field.Store.YES, Field.Index.ANALYZED, TermVector.WITH_POSITIONS_OFFSETS)); doc.add(new Field("html", this.getHtml(), Field.Store.YES, Field.Index.ANALYZED, TermVector.WITH_POSITIONS_OFFSETS)); return doc; } ......생략............... | cs |
Field의 매개변수는 org.apache.lucene.document.Field.Field(String name, String value, Store store, Index index, TermVector termVector) 또는 org.apache.lucene.document.Field.Field(String name, String value, Store store, Index index) 를 많이 쓴다.
store의 옵션은 총 2가지 이며, 'Field.Store.YES 는 value를 저장 할 것인다.' 이며
'Field.Store.NO 는 value를 저장 안 할 것인다.' 이다.
이말은 value는 단순히 Field의 plain text를 말하는 것이지 index된 값을 말하는것이 아니다.
Field.Index의 옵션은 총 3가지이며 NOT_ANALYZED,NO, ANALYZED 가 있다.
NOT_ANALYZED는 field의 값을 분석을 안한다는 말이며, plaintext의 값과 검색 시 비교는 할 수있다. rdb의 특정 컬럼 비교라고 생각 하면 된다.
NO의 경우는 검색을 지원하지 않는다. 단순한 값 저장 시 사용된다.
ANALYZED는 Field의 값을 분석을 하며 이 분석된 값을 색인으로 만든다.
TermVector의 경우, 색인의 특정 값을 보고자할때(?) 사실 본인의 경우 debugging용으로 사용 또는 term 추출 시 사용한다.
TemrVector는 index의 offset, 등장 횟수 등을 저장한다.
다음 글 부터 검색 과정을 예제 소스에 대해 자세히 설명하겠다.
루씬은 document기반의 저장방식으로 각 document의 field를 색인 하게 된다.
색인은 각 분석기의 특징대로 색인을 하며, 검색 시 그 색인을 기반으로 검색하게 된다.
db와 틀린점은 머 내생각이니 다음과 같은데...
1. db는 특정 컬럼에 값을 insert 한다는 개념이 강하다. 루씬은 insert 한다가 아닌
특정 컬럼을 어떻게 색인할 것인가로 접근하는게 맞는듯 보인다.
2. field추가가 자유롭다. 여느 nosql도 마찬가지겠지만, 루씬 역시, 특정 컬럼을 추가할 때 field를 추가하면된다.
3. 색인은 특정 값이 아닌 문장 단위의 것들로 한다. 물론 아닐경우도 있지만, 색인은 문장 자체를 설정된 분석기로 색인을 하는것이다.
이때문에 단순한 컬럼은 색인을 하지 않는다. 이유는 !! 검색엔진 이니까!
4. 검색 시 쿼리는 가공(?)을 해야한다. 물론 단순한 값을 할 경우는 필요없지만, lucene을 제대로 사용할려면, 검색 키워드를 가공을 하여 검색할 경우 더 큰 빚을 발휘 하는듯 보인다. ex) lucene 를 검색 시 lucening로 검색 하면 좋지 않을까? 머 이딴거.....
머 이정도 인듯 보인다.
위에 그림은 전형적인 루씬의 그림으로 index는 index document 과정이 필요하고, 검색 시는 search가 필요하다.
ps: 아마도 뒤에 lucene 관련 내용은 3.6 기반으로 설명할 것이다.(버전이 중요함.. ㅠㅠ)
lucene 과 마찬가지로 몽고 디비 역시 update는 미존재 한다. 그러나 api 는 지원 고로 remove후 다시 쓴다는 개념이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //update db.userCollection.update( { "user": "zest133" }, { "user" : "gno", "name" :"gno", "phone" : "111-1111-1111", "idx" : 1 } } //select all db.userCollection.find() | cs |
위에 코드와 같이 첫번째 object는 set을 의미 , 두번째 object는 where절 쯤 (?) 으로 생각.
쿼리를 날리고 결과를 확인하면 기존의 row가 두번재 object 형태로 변경된다. 이때, 이상한 점이 발견될 듯. update가 아니라 걍 delete 후 insert한 결과 형태로 변경된다.
그럼 변경하고 싶은 컬럼만 바꾸고 싶다면? 다음과 같이 하면 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //update db.userCollection.update( { "user": "gno" }, { $set :{ "user" : "gno", "name" :"gno", "phone" : "111-1111-1111", "idx" : 1 } } ) //select all db.userCollection.find() | cs |
두번째 object 에 $set이라는 내장 변수(?)를 써서 쿼리를 던지면 rdb의 update처럼 변경된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //$inc = plus, minus //$mul = mutiply, divide // db.userCollection.update( { "user": "gno" }, { $mul :{ "idx" : 1/2 } } ) | cs |
또, 숫자를 변경하고 싶다면, $mul을 사용해서 사용.
1 2 3 4 5 6 7 8 9 10 11 | db.userCollection.update( { "user": "gno" }, { $unset :{ "phone" : 1 } } ) | cs |
특정 컬럼을 제거 하고 싶다면 $unset을 해주고 컬럼 : 1 을 해준다. '1'은 true라는 개념인듯 하다.
1 2 3 4 5 6 7 8 9 10 | db.userCollection.update( { "user": "gno" }, { $set :{ "family" : ['mom','bro','sis'] } } ) | cs |
배열 형태로 바꾸거나 추가 할 컬럼은 위와 같이 사용하면된다.
삭제시 remove 라는 api를 이용해 삭제
1 2 3 4 5 6 | //delete db.userCollection.remove( { "user":"gno" } ) | cs |
몽고 db는 기본적으로 json 구조를 쓰며 js와 매우 흡사한 형태(?)로 query 를 날린다.
내부 api를 이용하여 만드는 구조인듯 보인다.
머 몽고 db역시 document 구조라 lucene과 비슷한 형태
Collection은 table, document 는 일종의 row , column은 field로 칭한다.
다음과 같이 쿼리를 날리면 특정 db를 사용하게 된다. 만약 db가 없으면 생성하게 된다.
1 2 | use testDB | cs |
insert 시 db.사용할 컬렉션.insert() 를 하면 row가 생성된다. 이때, 컬렉션이 존재 하지 않으면 생성 하면서 저장하게 된다.
type은 string, date, double 를 지원한듯 보인다.
1 2 3 4 5 6 7 8 9 10 11 | //insert query db.userCollection.insert( { "user":"zest133", "pwd" :"zest133", "name" :"zest133", "email": "zest133@test.com", "date" : new Date() } ) | cs |
색인 컬럼은 다음과 같이 설정.
1 2 3 4 5 6 7 | //insert index db.userCollection.ensureIndex( { "user" : 1 } ) | cs |
배열 색인은 다음과 같이 설정.
1 2 3 4 5 6 | //create array index db.userCollection.createIndex( { "family" : 1 } ) | cs |
createIndex를 사용하여, 특정 json array 컬럼 :1 을 하면된다. 재미난 점은 배열안에 값들이 내부적으로 색인이 된다.
압축 해제하고 서버 실행하면 끝이다.
서버 실행할때 커맨드 라인으로 옵션을 입력하거나 미리 설정파일을 만들어 놓고 사용 할 수 있다.
Mongo 설정 파일 yml 구조를 사용.
tab 없이 스페이스로만 영역을 설정. 머 이런것들 어려우니 작업후 yaml validator로 검증하는게 빠르다.
단일 서버 실행용.
linux 특정 위치에 특정 설정 파일을 생성.
ex) vi mongo.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #yml 파일이 존재 하지 않으면 /var/local/mongdb/data 에 data를 저장. (경로도 마찬가지로 없으면 default 경로에 저장.) #log역시 설정 정보가 없으면 /var/local/mongdb/logs/log.log에 저장. #net - network 설정#하위 구조로 bindIp와 port를 설정한다. #bindIP는 mongoDB 자신의 ip를 설정. #port는 mongDB 의 port를 설정. net: bindIp: "192.168.0.70" port: 35001 #processManagement - 실행 옵션. #fork 는 백그라운드 옵션. processManagement: fork: true #storage - data 저장 경로를 설정. #dbpath - data를 저장할 실제 경로. #journal - data를 쓰기 전 , data write query를 파일에 저장하는 옵션. (일종의 검증, 복구를 위한 작업인듯...) # enabled - journal 을 쓸지 말지의 설정. storage: dbPath: /root/mongo/data/repl1 journal: enabled: true #destination: file, syslog 2가지 옵션 사용 가능 #file로 선언하면 path 옵션을 필수로 넣어서 경로를 직접 설정 #syslog로 선언하면 경로 설정 없이 디폴트 로그파일에 저장 ##verbosity: 로그 기록 레벨 # default : 0 # 0 ~ 5 숫자 값으로 레벨 구분 # 0 : all # 1 : debug, # 2: information # 3: warning # 4: errorm # 5: fatalsystem systemLog: verbosity: 1 destination: file logAppend: true path: /root/mongo/log/repl_log1.log | cs |
마지막으로 실행해보자.
./bin/mongd -f mongo.yml