/*
* Copyright 2013 Websquared, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.fastcatsearch.ir.settings;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.fastcatsearch.ir.common.IRException;
import org.fastcatsearch.ir.field.AStringField;
import org.fastcatsearch.ir.field.AStringMvField;
import org.fastcatsearch.ir.field.DatetimeField;
import org.fastcatsearch.ir.field.DoubleField;
import org.fastcatsearch.ir.field.DoubleMvField;
import org.fastcatsearch.ir.field.Field;
import org.fastcatsearch.ir.field.FieldDataParseException;
import org.fastcatsearch.ir.field.FloatField;
import org.fastcatsearch.ir.field.FloatMvField;
import org.fastcatsearch.ir.field.IntField;
import org.fastcatsearch.ir.field.IntMvField;
import org.fastcatsearch.ir.field.LongField;
import org.fastcatsearch.ir.field.LongMvField;
import org.fastcatsearch.ir.field.UStringField;
import org.fastcatsearch.ir.field.UStringMvField;
import org.fastcatsearch.ir.io.IOUtil;
import org.fastcatsearch.util.HTMLTagRemover;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@XmlRootElement(name = "field")
// propOrder는 xml writer의 기록순서인데, attribute의 경우 next attribute를 현재 attribute의 앞에 기록하므로 proporder를 거꾸로 정의해야 올바른 순서로 보여진다.
@XmlType(propOrder = { "multiValueDelimiter", "multiValue", "modify", "removeTag", "compress", "store", "size", "name", "source", "type", "id" })
public class FieldSetting {
protected static Logger logger = LoggerFactory.getLogger(FieldSetting.class);
private String id;
private String name;
private Type type;
private int size;
private String source;
private boolean store = true;
private boolean compress;
private boolean removeTag;
private boolean modify;
private boolean multiValue;
private String multiValueDelimiter;
public static enum Type {
UNKNOWN, ASTRING, STRING, INT, LONG, FLOAT, DOUBLE, DATETIME, _SCORE, _HIT, _DOCNO, _BUNDLESIZE, _DISTANCE
}
// JAXB를 위해서는 default 생성자가 꼭 필요하다.
public FieldSetting() {
}
public FieldSetting(String id, String name, Type type) {
this.id = id.toUpperCase();
this.name = name;
this.type = type;
}
@Override
public String toString() {
return "[FieldSetting]" + id + ", type=" + type + ", source=" + source + ", size=" + size + ", mv=" + multiValue;
}
@XmlAttribute(required = true)
public String getId() {
return id;
}
public void setId(String id) {
this.id = id.toUpperCase();
}
@XmlAttribute
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlAttribute(required = true)
public Type getType() {
return type;
}
public void setType(Type type) {
this.type = type;
}
@XmlAttribute
@XmlJavaTypeAdapter(OptionalStringAdapter.class)
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source.toUpperCase();
}
@XmlAttribute
@XmlJavaTypeAdapter(OptionalIntPositiveAdapter.class)
public Integer getSize() {
return size;
}
public void setSize(Integer size) {
this.size = size;
}
@XmlAttribute
@XmlJavaTypeAdapter(OptionalBooleanTrueAdapter.class)
//기본적으로 저장 true;
public Boolean isStore() {
return store;
}
public void setStore(Boolean store) {
this.store = store;
}
@XmlAttribute
@XmlJavaTypeAdapter(OptionalBooleanFalseAdapter.class)
public Boolean isCompress() {
return compress;
}
public void setCompress(Boolean compress) {
this.compress = compress;
}
@XmlAttribute
@XmlJavaTypeAdapter(OptionalBooleanFalseAdapter.class)
public Boolean isRemoveTag() {
return removeTag;
}
public void setRemoveTag(Boolean removeTag) {
this.removeTag = removeTag;
}
@XmlAttribute
@XmlJavaTypeAdapter(OptionalBooleanFalseAdapter.class)
public Boolean isModify() {
return modify;
}
public void setModify(Boolean modify) {
this.modify = modify;
}
@XmlAttribute
@XmlJavaTypeAdapter(OptionalBooleanFalseAdapter.class)
public Boolean isMultiValue() {
return multiValue;
}
public void setMultiValue(Boolean multiValue) {
this.multiValue = multiValue;
}
@XmlAttribute
public String getMultiValueDelimiter() {
return multiValueDelimiter;
}
public void setMultiValueDelimiter(String multiValueDelimiter) {
this.multiValueDelimiter = multiValueDelimiter;
}
//sz가 0보다 크면 sz를 사용하고 아니면 기존 size를 사용한다.
public int getByteSize(int sz) {
// string필드의 경우만 sz를 설정할수 있으며, 나머지 필드는 사이즈 셋팅이 불가능하다.
if (type == Type.STRING) {
if (sz > 0) {
return sz * 2;
}
} else if (type == Type.ASTRING) {
if (sz > 0) {
return sz;
}
}
return getByteSize();
}
public int getByteSize() {
if (type == Type.INT)
return IOUtil.SIZE_OF_INT;
else if (type == Type.LONG)
return IOUtil.SIZE_OF_LONG;
else if (type == Type.FLOAT)
return IOUtil.SIZE_OF_INT;
else if (type == Type.DOUBLE)
return IOUtil.SIZE_OF_LONG;
else if (type == Type.DATETIME)
return IOUtil.SIZE_OF_LONG;
else if (type == Type.STRING)
return size * 2;
else if (type == Type.ASTRING)
return size;
return size;
}
// 빈 데이터 필드생성. 디스크나 네트워크에서 문서를 읽기전에 빈 객체 필요시 사용.
public Field createEmptyField() {
Field field = null;
try {
field = createIndexableField(null);
} catch (FieldDataParseException e) {
// data가 null일 경우 parse exception은 발생하지 않으므로 무시.
logger.error("createField 에러.", e);
}
return field;
}
public Field createIndexableField(Object dataObject) throws FieldDataParseException {
return createIndexableField(dataObject, null);
}
public Field createIndexableField(Object dataObject, String multiValueDelimiter) throws FieldDataParseException {
String data = null;
if (dataObject != null) {
if(dataObject instanceof String){
data = (String) dataObject;
}else{
data = dataObject.toString();
}
if(removeTag){
try{
data = HTMLTagRemover.clean(data);
}catch(IRException e){
throw new FieldDataParseException(e);
}
}
}
Field field = null;
if (type == FieldSetting.Type.INT) {
if (multiValue) {
field = new IntMvField(id, data);
} else {
field = new IntField(id, data);
}
} else if (type == FieldSetting.Type.LONG) {
if (multiValue) {
field = new LongMvField(id, data);
} else {
field = new LongField(id, data);
}
} else if (type == FieldSetting.Type.FLOAT) {
if (multiValue) {
field = new FloatMvField(id, data);
} else {
field = new FloatField(id, data);
}
} else if (type == FieldSetting.Type.DOUBLE) {
if (multiValue) {
field = new DoubleMvField(id, data);
} else {
field = new DoubleField(id, data);
}
} else if (type == FieldSetting.Type.DATETIME) {
return new DatetimeField(id, data);
} else if (type == FieldSetting.Type.ASTRING) {
if (multiValue) {
field = new AStringMvField(id, data, size);
} else {
field = new AStringField(id, data, size);
}
} else if (type == FieldSetting.Type.STRING) {
if (multiValue) {
field = new UStringMvField(id, data, size);
} else {
field = new UStringField(id, data, size);
}
}
if (field == null) {
throw new RuntimeException("지원하지 않는 필드타입입니다. Type = " + type);
}
// 필드스트링을 색인이 용이한 data로 변환한다.
field.parseIndexable(multiValueDelimiter);
return field;
}
//create variable size data field
public Field createPatternField(String data) throws FieldDataParseException {
return createSingleValueField(data, data.length());
}
//create fixed size data field
public Field createPrimaryKeyField(String data) throws FieldDataParseException {
return createSingleValueField(data, 0);
}
public Field createSingleValueField(String data, int length) throws FieldDataParseException {
if (type == FieldSetting.Type.INT) {
return new IntField(id, data).parseIndexable();
} else if (type == FieldSetting.Type.LONG) {
return new LongField(id, data).parseIndexable();
} else if (type == FieldSetting.Type.FLOAT) {
return new FloatField(id, data).parseIndexable();
} else if (type == FieldSetting.Type.DOUBLE) {
return new DoubleField(id, data).parseIndexable();
} else if (type == FieldSetting.Type.DATETIME) {
return new DatetimeField(id, data).parseIndexable();
} else if (type == FieldSetting.Type.ASTRING) {
if (length > 0) {
return new AStringField(id, data, length).parseIndexable();
} else {
return new AStringField(id, data, size).parseIndexable();
}
} else if (type == FieldSetting.Type.STRING) {
if (length > 0) {
return new UStringField(id, data, length).parseIndexable();
} else {
return new UStringField(id, data, size).parseIndexable();
}
}
throw new RuntimeException("지원하지 않는 필드타입입니다. Type = " + type);
}
public boolean isVariableField() {
if (type == FieldSetting.Type.ASTRING || type == FieldSetting.Type.STRING) {
return size <= 0;
}
return false;
}
public boolean isNumericField() {
return type == FieldSetting.Type.INT || type == FieldSetting.Type.LONG || type == FieldSetting.Type.FLOAT || type == FieldSetting.Type.DOUBLE
|| type == FieldSetting.Type.DATETIME || type == FieldSetting.Type._HIT || type == FieldSetting.Type._SCORE
|| type == FieldSetting.Type._DOCNO || type == Type._DISTANCE;
}
}