sunyj пре 9 година
родитељ
комит
65b08308fb
28 измењених фајлова са 801 додато и 955 уклоњено
  1. 18 62
      search-console/src/main/java/com/uas/search/console/controller/IndexController.java
  2. 5 6
      search-console/src/main/java/com/uas/search/console/controller/SearchController.java
  3. 1 10
      search-console/src/main/java/com/uas/search/console/dao/BrandSimpleInfoDao.java
  4. 0 8
      search-console/src/main/java/com/uas/search/console/dao/ComponentSimpleInfoDao.java
  5. 1 11
      search-console/src/main/java/com/uas/search/console/dao/KindSimpleInfoDao.java
  6. 0 18
      search-console/src/main/java/com/uas/search/console/dao/PropertyValueSimpleInfoDao.java
  7. 0 199
      search-console/src/main/java/com/uas/search/console/dcn/DCNListener.java
  8. 0 209
      search-console/src/main/java/com/uas/search/console/dcn/DCNRegistrationManager.java
  9. 129 0
      search-console/src/main/java/com/uas/search/console/jms/AQListener.java
  10. 149 0
      search-console/src/main/java/com/uas/search/console/jms/QueueMessageParser.java
  11. 58 0
      search-console/src/main/java/com/uas/search/console/jms/QueueMessageTypeFactory.java
  12. 1 12
      search-console/src/main/java/com/uas/search/console/model/BrandSimpleInfo.java
  13. 6 14
      search-console/src/main/java/com/uas/search/console/model/ComponentSimpleInfo.java
  14. 1 12
      search-console/src/main/java/com/uas/search/console/model/KindSimpleInfo.java
  15. 84 0
      search-console/src/main/java/com/uas/search/console/model/ParsedQueueMessage.java
  16. 119 0
      search-console/src/main/java/com/uas/search/console/model/PropertyValue.java
  17. 0 75
      search-console/src/main/java/com/uas/search/console/model/PropertyValueSimpleInfo.java
  18. 2 13
      search-console/src/main/java/com/uas/search/console/service/IndexService.java
  19. 53 174
      search-console/src/main/java/com/uas/search/console/service/impl/IndexServiceImpl.java
  20. 0 39
      search-console/src/main/java/com/uas/search/console/service/impl/SearchServiceImpl.java
  21. 0 37
      search-console/src/main/java/com/uas/search/console/support/ContextRefreshedProcessor.java
  22. 0 24
      search-console/src/main/java/com/uas/search/console/support/SysConf.java
  23. 165 0
      search-console/src/main/java/com/uas/search/console/util/MergeComponentData.java
  24. 3 17
      search-console/src/main/java/com/uas/search/console/util/SearchConstants.java
  25. 0 1
      search-console/src/main/resources/dev/sys.properties
  26. 0 1
      search-console/src/main/resources/prod/sys.properties
  27. 6 12
      search-console/src/main/resources/spring/applicationContext.xml
  28. 0 1
      search-console/src/main/resources/test/sys.properties

+ 18 - 62
search-console/src/main/java/com/uas/search/console/controller/IndexController.java

@@ -1,95 +1,51 @@
 package com.uas.search.console.controller;
 
-import org.apache.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.ResponseBody;
 
-import com.uas.search.console.dcn.DCNRegistrationManager;
+import com.uas.search.console.jms.AQListener;
 import com.uas.search.console.service.IndexService;
 
 /**
  * 索引创建相关请求
- * 
  * @author sunyj
  * @since 2016年8月5日 上午11:42:54
  */
 @Controller
 @RequestMapping("/index")
 public class IndexController {
-
+	
 	@Autowired
 	private IndexService indexService;
-
+	
 	@Autowired
-	private DCNRegistrationManager dcnRegistrationManager;
-
-	private Logger logger = Logger.getLogger(IndexController.class);
-
+	private AQListener aqListener;
+	
 	/**
-	 * 创建索引
+	 * 初始化创建索引文件
 	 * 
-	 * @param fromDB
-	 *            器件数据的来源是否为数据库,为1表示从数据库获取,为null或其他值表示从本地文件获取
 	 * @return 所用时间 ms
 	 */
 	@RequestMapping("/create")
 	@ResponseBody
-	public String createIndexes(Integer fromDB) {
-		return "Indexes created success in " + indexService.createIndexes(fromDB) + " ms.";
-	}
-
-	/**
-	 * 开启实时更新索引的程序
-	 * 
-	 * @return
-	 */
-	@RequestMapping("/realTimeUpdate")
-	@ResponseBody
-	public String registerDatabaseChangeNotification() {
-		return dcnRegistrationManager.registerDataChangeNotification();
-	}
-
-	/**
-	 * 开启实时更新索引的程序
-	 * 
-	 * @return
-	 */
-	@RequestMapping("/realTimeUpdate/start")
-	@ResponseBody
-	public String startRegisterDatabaseChangeNotification() {
-		return dcnRegistrationManager.registerDataChangeNotification();
+	public String initIndexes() {
+		return "Indexes created success in " + indexService.createIndexs() + " ms.";
 	}
-
+	
 	/**
-	 * 关闭实时更新索引的程序
-	 * 
+	 * 实时更新索引
 	 * @return
 	 */
-	@RequestMapping("/realTimeUpdate/stop")
-	@ResponseBody
-	public String unregisterDatabaseChangeNotification() {
-		return dcnRegistrationManager.unregisterDataChangeNotification();
-	}
-
-	/**
-	 * 重启实时更新索引的程序
-	 * 
-	 * @return
-	 */
-	@RequestMapping("/realTimeUpdate/restart")
-	@ResponseBody
-	public String restartRegisterDatabaseChangeNotification() {
-		dcnRegistrationManager.unregisterDataChangeNotification();
-		return dcnRegistrationManager.registerDataChangeNotification();
-	}
-
-	@RequestMapping("/downloadComponentData")
+	@RequestMapping("/listen")
 	@ResponseBody
-	public String downloadComponentData(Integer startFileIndex) {
-		Long size = indexService.downloadComponentData(startFileIndex);
-		logger.info("Downloading finished, components' size " + size);
-		return "Components' size: " + size;
+	public String listen(){
+		new Thread(){
+			public void run() {
+				aqListener.execute();
+			};
+		}.start();
+		return "Listen...";
 	}
 }

+ 5 - 6
search-console/src/main/java/com/uas/search/console/controller/SearchController.java

@@ -132,23 +132,22 @@ public class SearchController {
 	public List<Map<String, Object>> getSimilarKinds(String kindName) {
 		return searchService.getSimilarKinds(kindName);
 	}
-
+	
 	@RequestMapping("/similarLeafKinds")
 	@ResponseBody
-	public List<Map<String, Object>> getSimilarLeafKinds(String kindName) {
+	public List<Map<String, Object>> getSimilarLeafKinds(String kindName){
 		return searchService.getSimilarLeafKinds(kindName);
 	}
 
 	@RequestMapping("/similarKindsByLevel")
 	@ResponseBody
-	public List<Map<String, Object>> getSimilarKindsByLevel(String kindName, Short level) {
+	public List<Map<String, Object>> getSimilarKindsByLevel(String kindName, Short level){
 		return searchService.getSimilarKindsByLevel(kindName, level);
 	}
-
+	
 	@RequestMapping("/similarPropertyValues")
 	@ResponseBody
-	public List<Map<String, String>> getSimilarPropertyValues(Long kindId, Long propertyId, String keyword,
-			Long topNum) {
+	public List<Map<String, String>> getSimilarPropertyValues(Long kindId, Long propertyId, String keyword, Long topNum) {
 		return searchService.getSimilarPropertyValues(kindId, propertyId, keyword, topNum);
 	}
 }

+ 1 - 10
search-console/src/main/java/com/uas/search/console/dao/BrandSimpleInfoDao.java

@@ -20,14 +20,5 @@ public interface BrandSimpleInfoDao
 	 * @param id
 	 * @return
 	 */
-	// TODO DCN测试完成后删除
-	// public BrandSimpleInfo findById(Long id);
-
-	/**
-	 * 根据rowid获取品牌
-	 * 
-	 * @param rowid
-	 * @return
-	 */
-	public BrandSimpleInfo findByRowid(String rowid);
+	public BrandSimpleInfo findById(Long id);
 }

+ 0 - 8
search-console/src/main/java/com/uas/search/console/dao/ComponentSimpleInfoDao.java

@@ -26,14 +26,6 @@ public interface ComponentSimpleInfoDao
 	 */
 	public ComponentSimpleInfo findById(Long id);
 
-	/**
-	 * 根据rowid获取器件
-	 * 
-	 * @param rowid
-	 * @return
-	 */
-	public ComponentSimpleInfo findByRowid(String rowid);
-
 	/**
 	 * 根据类目kindid获取器件
 	 * 

+ 1 - 11
search-console/src/main/java/com/uas/search/console/dao/KindSimpleInfoDao.java

@@ -20,15 +20,5 @@ public interface KindSimpleInfoDao
 	 * @param id
 	 * @return
 	 */
-	// TODO DCN测试完成后删除
-	// public KindSimpleInfo findById(Long id);
-
-	/**
-	 * 根据rowid获取类目
-	 * 
-	 * @param rowid
-	 * @return
-	 */
-	public KindSimpleInfo findByRowid(String rowid);
-
+	public KindSimpleInfo findById(Long id);
 }

+ 0 - 18
search-console/src/main/java/com/uas/search/console/dao/PropertyValueSimpleInfoDao.java

@@ -1,18 +0,0 @@
-package com.uas.search.console.dao;
-
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.data.repository.query.Param;
-import org.springframework.stereotype.Repository;
-
-import com.uas.search.console.model.PropertyValueSimpleInfo;
-import com.uas.search.console.util.SearchConstants;
-
-@Repository
-public interface PropertyValueSimpleInfoDao
-		extends JpaSpecificationExecutor<PropertyValueSimpleInfo>, JpaRepository<PropertyValueSimpleInfo, Long> {
-	@Query(value = "select pv_componentid from " + SearchConstants.PROPERTYVALUE_TABLE_NAME
-			+ " where rowid = :rowid", nativeQuery = true)
-	public Long findComponentIdByRowid(@Param("rowid") String rowid);
-}

+ 0 - 199
search-console/src/main/java/com/uas/search/console/dcn/DCNListener.java

@@ -1,199 +0,0 @@
-package com.uas.search.console.dcn;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.log4j.Logger;
-
-import com.uas.search.console.core.util.ContextUtils;
-import com.uas.search.console.dao.BrandSimpleInfoDao;
-import com.uas.search.console.dao.ComponentSimpleInfoDao;
-import com.uas.search.console.dao.KindSimpleInfoDao;
-import com.uas.search.console.dao.PropertyValueSimpleInfoDao;
-import com.uas.search.console.model.BrandSimpleInfo;
-import com.uas.search.console.model.ComponentSimpleInfo;
-import com.uas.search.console.model.KindSimpleInfo;
-import com.uas.search.console.service.IndexService;
-import com.uas.search.console.util.SearchConstants;
-import com.uas.search.service.SearchService;
-
-import oracle.jdbc.dcn.DatabaseChangeEvent;
-import oracle.jdbc.dcn.DatabaseChangeListener;
-import oracle.jdbc.dcn.QueryChangeDescription;
-import oracle.jdbc.dcn.RowChangeDescription;
-import oracle.jdbc.dcn.RowChangeDescription.RowOperation;
-import oracle.jdbc.dcn.TableChangeDescription;
-import oracle.sql.ROWID;
-
-/**
- * 接收Oracle数据变化的通知推送
- * 
- * @author sunyj
- * @since 2016年9月14日 上午9:54:18
- */
-public class DCNListener implements DatabaseChangeListener {
-
-	private IndexService indexService;
-
-	private SearchService searchService;
-
-	private KindSimpleInfoDao kindDao;
-
-	private BrandSimpleInfoDao brandDao;
-
-	private ComponentSimpleInfoDao componentDao;
-
-	private PropertyValueSimpleInfoDao propertyValueDao;
-
-	private Logger logger = Logger.getLogger(DCNListener.class);
-
-	public DCNListener() {
-		indexService = ContextUtils.getBean(IndexService.class);
-		// 有两个SearchService bean:
-		// searchService用于dubbo服务,searchServiceImpl来自@Service
-		searchService = ContextUtils.getApplicationContext().getBean("searchService", SearchService.class);
-		kindDao = ContextUtils.getBean(KindSimpleInfoDao.class);
-		brandDao = ContextUtils.getBean(BrandSimpleInfoDao.class);
-		componentDao = ContextUtils.getBean(ComponentSimpleInfoDao.class);
-		propertyValueDao = ContextUtils.getBean(PropertyValueSimpleInfoDao.class);
-	}
-
-	@Override
-	public void onDatabaseChangeNotification(DatabaseChangeEvent event) {
-		QueryChangeDescription[] queryChangeDescriptions = event.getQueryChangeDescription();
-		for (QueryChangeDescription description : queryChangeDescriptions) {
-			TableChangeDescription[] tableChangeDescriptions = description.getTableChangeDescription();
-			for (TableChangeDescription tableChangeDescription : tableChangeDescriptions) {
-				String tableName = tableChangeDescription.getTableName();
-				logger.info("tableName: " + tableName);
-				RowChangeDescription[] rowChangeDescriptions = tableChangeDescription.getRowChangeDescription();
-				for (RowChangeDescription rowChangeDescription : rowChangeDescriptions) {
-					RowOperation rowOperation = rowChangeDescription.getRowOperation();
-					logger.info("rowOperation " + rowOperation);
-					ROWID rowid = rowChangeDescription.getRowid();
-					logger.info("rowid: " + rowid);
-					realTimeUpdateIndex(tableName, rowOperation, rowid.stringValue());
-				}
-			}
-		}
-	}
-
-	/**
-	 * 根据表的变化更新索引
-	 * 
-	 * @param tableName
-	 * @param rowOperation
-	 * @param rowid
-	 */
-	private void realTimeUpdateIndex(String tableName, RowOperation rowOperation, String rowid) {
-		// propertyvalue表变化,只涉及器件索引的更新,与其他表的变化不同
-		if (tableName.contains(SearchConstants.PROPERTYVALUE_TABLE_NAME.toUpperCase())) {
-			realTimeUpdateComponentIndex(rowOperation, rowid);
-		} else {
-			if (rowOperation.equals(RowOperation.DELETE)) {
-				indexService.delete(getObject(tableName, rowid));
-			} else if (rowOperation.equals(RowOperation.INSERT)) {
-				indexService.save(getObject(tableName, rowid));
-			} else if (rowOperation.equals(RowOperation.UPDATE)) {
-				indexService.update(getObject(tableName, rowid));
-			} else {
-				logger.error("DCN error: tableName " + tableName + " " + rowOperation + " rowid " + rowid);
-			}
-		}
-	}
-
-	/**
-	 * 根据属性值表的变化更新器件索引
-	 * 
-	 * @param rowOperation
-	 * @param propertyValueRowid
-	 */
-	private void realTimeUpdateComponentIndex(RowOperation rowOperation, String propertyValueRowid) {
-		// 属性值表变化,最终还是要更新其所属器件的索引
-		// 插入和更新可通过查询数据库获知相应器件的id
-		// 而删除操作需从本地索引中获取器件rowid,再根据rowid更新索引
-		ComponentSimpleInfo component = null;
-
-		// 属性值表变化为插入或更新操作
-		if (!rowOperation.equals(RowOperation.DELETE)) {
-			Long componentId = propertyValueDao.findComponentIdByRowid(propertyValueRowid);
-			if (componentId == null) {
-				logger.error("数据库中未找到属性值rowid: " + propertyValueRowid + " 所对应的器件");
-			} else {
-				component = componentDao.findById(componentId);
-				if (component == null) {
-					logger.error("数据库中未找到器件id: " + componentId + " 所对应的器件");
-				}
-				// 更新器件索引
-				else {
-					indexService.update(component);
-				}
-			}
-		}
-		// 属性值表变化为删除操作
-		else {
-			// 从本地获取component的rowid
-			String componentRowid = searchService.getComponentRowidByPropertyValueRowid(propertyValueRowid);
-			if (StringUtils.isEmpty(componentRowid)) {
-				// 当同一个器件的属性值在一次事务中有多个变化时,
-				// 因为第一次变化时便已更新了索引,
-				// 之后的属性值DELETE操作,
-				// 在本地是无法根据属性值rowid找到对应的器件的,
-				// 于是会报下列的错,但实际索引是正确的,这种情况下不必在意
-				logger.error("本地索引中未找到属性值rowid: " + propertyValueRowid + " 所对应的器件");
-			} else {
-				// 根据rowid获取器件
-				component = componentDao.findByRowid(componentRowid);
-				// 存在,更新器件索引
-				if (component != null) {
-					indexService.update(component);
-				}
-				// 不存在,删除本地索引中的器件
-				else {
-					component = new ComponentSimpleInfo();
-					component.setRowid(propertyValueRowid);
-					indexService.delete(component);
-				}
-			}
-		}
-	}
-
-	/**
-	 * 根据表的变化获得类目、品牌或器件对象
-	 * 
-	 * @param tableName
-	 * @param rowid
-	 * @return
-	 */
-	private Object getObject(String tableName, String rowid) {
-		// tableName可能为 UUPLATFORMDEMO.PRODUCT$COMPONENT
-		// kind表数据变化
-		if (tableName.contains(SearchConstants.KIND_TABLE_NAME.toUpperCase())) {
-			KindSimpleInfo kind = kindDao.findByRowid(rowid);
-			if (kind == null) {
-				kind = new KindSimpleInfo();
-				kind.setRowid(rowid);
-			}
-			return kind;
-		}
-		// brand表变化
-		else if (tableName.contains(SearchConstants.BRAND_TABLE_NAME.toUpperCase())) {
-			BrandSimpleInfo brand = brandDao.findByRowid(rowid);
-			if (brand == null) {
-				brand = new BrandSimpleInfo();
-				brand.setRowid(rowid);
-			}
-			return brand;
-		}
-		// component表变化
-		else if (tableName.contains(SearchConstants.COMPONENT_TABLE_NAME.toUpperCase())) {
-			ComponentSimpleInfo component = componentDao.findByRowid(rowid);
-			if (component == null) {
-				component = new ComponentSimpleInfo();
-				component.setRowid(rowid);
-			}
-			return component;
-		} else {
-			logger.error("DCN error: tableName: " + tableName + " rowid: " + rowid);
-		}
-		return null;
-	}
-}

+ 0 - 209
search-console/src/main/java/com/uas/search/console/dcn/DCNRegistrationManager.java

@@ -1,209 +0,0 @@
-package com.uas.search.console.dcn;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.Properties;
-
-import org.apache.commons.dbcp.BasicDataSource;
-import org.apache.log4j.Logger;
-import org.springframework.stereotype.Service;
-
-import com.uas.search.console.core.util.ContextUtils;
-import com.uas.search.console.util.SearchConstants;
-
-import oracle.jdbc.OracleConnection;
-import oracle.jdbc.OracleDriver;
-import oracle.jdbc.OracleStatement;
-import oracle.jdbc.dcn.DatabaseChangeRegistration;
-
-/**
- * 注册DatabaseChangeNotification,以便获取Oracle数据变化的通知
- * 
- * @author sunyj
- * @since 2016年9月14日 上午9:52:20
- */
-@Service
-public class DCNRegistrationManager {
-
-	private static DatabaseChangeRegistration dcnRegistration;
-
-	private Logger logger = Logger.getLogger(DCNRegistrationManager.class);
-
-	/**
-	 * 注册DatabaseChangeNotification
-	 */
-	public String registerDataChangeNotification() {
-		String message = "";
-		if (dcnRegistration != null) {
-			message = "已存在注册的DCN: " + dcnRegistration.getRegId();
-			logger.info(message);
-			return message;
-		}
-
-		unregisterOldDCNsInDatabase();
-
-		OracleConnection connection = null;
-		Statement statement = null;
-		try {
-			connection = getConnection();
-
-			String localHost = InetAddress.getLocalHost().getHostAddress();
-
-			// 根据配置注册DatabaseChangeNotification
-			Properties properties = new Properties();
-			properties.setProperty(OracleConnection.DCN_NOTIFY_ROWIDS, "true");
-			properties.setProperty(OracleConnection.DCN_QUERY_CHANGE_NOTIFICATION, "true");
-			// 设置监听程序的ip
-			properties.setProperty(OracleConnection.NTF_LOCAL_HOST, localHost);
-			// 设置超时为永不过期
-			properties.setProperty(OracleConnection.NTF_TIMEOUT, "0");
-			dcnRegistration = connection.registerDatabaseChangeNotification(properties);
-
-			// 绑定DCNListener
-			DCNListener dcnListener = new DCNListener();
-			dcnRegistration.addListener(dcnListener);
-
-			statement = connection.createStatement();
-			((OracleStatement) statement).setDatabaseChangeRegistration(dcnRegistration);
-
-			// 监测component、kind、brand、propertyvalue表变化
-			statement.execute("select cmp_id, cmp_uuid, cmp_code, cmp_kiid, cmp_brid from "
-					+ SearchConstants.COMPONENT_TABLE_NAME);
-			statement.execute("select ki_id, ki_name, ki_level, ki_isleaf from " + SearchConstants.KIND_TABLE_NAME);
-			statement.execute("select br_id, br_uuid, br_name_cn, br_name_en from " + SearchConstants.BRAND_TABLE_NAME);
-			statement
-					.execute("select pv_id, pv_componentid, pv_value from " + SearchConstants.PROPERTYVALUE_TABLE_NAME);
-
-			message = "成功注册DCN: id=" + dcnRegistration.getRegId() + ", ip=" + localHost;
-			logger.info(message);
-			String[] tables = dcnRegistration.getTables();
-			for (String table : tables) {
-				logger.info("注册DCN: " + table);
-			}
-		} catch (SQLException | UnknownHostException e) {
-			// 出现异常,取消注册DCN
-			if (connection != null && dcnRegistration != null) {
-				try {
-					message = "出现SQLException或UnknownHostException,取消注册DCN: " + dcnRegistration.getRegId();
-					logger.error(message);
-					connection.unregisterDatabaseChangeNotification(dcnRegistration);
-				} catch (SQLException e1) {
-					message = "取消注册DCN失败: " + dcnRegistration.getRegId();
-					logger.error(message);
-					e1.printStackTrace();
-				} finally {
-					dcnRegistration = null;
-				}
-			}
-			e.printStackTrace();
-		} finally {
-			if (statement != null) {
-				try {
-					statement.close();
-				} catch (SQLException e) {
-					e.printStackTrace();
-				}
-			}
-			if (connection != null) {
-				try {
-					connection.close();
-				} catch (SQLException e) {
-					e.printStackTrace();
-				}
-			}
-		}
-		return message;
-	}
-
-	/**
-	 * 取消注册DatabaseChangeNotification
-	 */
-	public String unregisterDataChangeNotification() {
-		String message = "";
-		if (dcnRegistration == null) {
-			message = "DCN未注册或已被取消注册";
-			logger.info(message);
-			return message;
-		}
-		OracleConnection connection = null;
-		try {
-			connection = getConnection();
-			if (connection != null) {
-				connection.unregisterDatabaseChangeNotification(dcnRegistration);
-				message = "成功取消注册DCN: " + dcnRegistration.getRegId();
-				logger.info(message);
-			}
-		} catch (SQLException e) {
-			message = "取消注册DCN失败: " + dcnRegistration.getRegId();
-			logger.error(message);
-			e.printStackTrace();
-		} finally {
-			dcnRegistration = null;
-			if (connection != null) {
-				try {
-					connection.close();
-				} catch (SQLException e) {
-					e.printStackTrace();
-				}
-			}
-		}
-		return message;
-	}
-
-	/**
-	 * 获取数据库连接
-	 * 
-	 * @return
-	 * @throws SQLException
-	 */
-	private OracleConnection getConnection() throws SQLException {
-		BasicDataSource dataSource = ContextUtils.getApplicationContext().getBean("dataSource", BasicDataSource.class);
-		Properties oracleProperties = new Properties();
-		oracleProperties.setProperty(OracleConnection.CONNECTION_PROPERTY_USER_NAME, dataSource.getUsername());
-		oracleProperties.setProperty(OracleConnection.CONNECTION_PROPERTY_PASSWORD, dataSource.getPassword());
-		return (OracleConnection) new OracleDriver().connect(dataSource.getUrl(), oracleProperties);
-	}
-
-	/**
-	 * 清理数据库中的DCN注册(因程序未正确关闭)
-	 */
-	private void unregisterOldDCNsInDatabase() {
-		OracleConnection connection = null;
-		Statement statement = null;
-		try {
-			connection = getConnection();
-			statement = connection.createStatement();
-			String localHost = InetAddress.getLocalHost().getHostAddress();
-			ResultSet resultSet = statement
-					.executeQuery("select regid, callback from user_change_notification_regs where callback like '%"
-							+ localHost + "%'");
-			while (resultSet.next()) {
-				Long regId = resultSet.getLong(1);
-				String callback = resultSet.getString(2);
-				connection.unregisterDatabaseChangeNotification(regId, callback);
-				logger.info("成功清理数据库中的DCN: regId=" + regId + " callback=" + callback);
-			}
-		} catch (SQLException | UnknownHostException e) {
-			logger.info("清理数据库DCN失败");
-			e.printStackTrace();
-		} finally {
-			if (statement != null) {
-				try {
-					statement.close();
-				} catch (SQLException e) {
-					e.printStackTrace();
-				}
-			}
-			if (connection != null) {
-				try {
-					connection.close();
-				} catch (SQLException e) {
-					e.printStackTrace();
-				}
-			}
-		}
-	}
-}

+ 129 - 0
search-console/src/main/java/com/uas/search/console/jms/AQListener.java

@@ -0,0 +1,129 @@
+package com.uas.search.console.jms;
+
+import java.sql.SQLException;
+import java.util.Properties;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.Queue;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.Session;
+
+import org.apache.commons.dbcp.BasicDataSource;
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.alibaba.fastjson.JSONException;
+import com.uas.search.console.core.util.ContextUtils;
+import com.uas.search.console.model.ParsedQueueMessage;
+import com.uas.search.console.service.IndexService;
+import com.uas.search.console.util.SearchConstants;
+
+import oracle.jms.AQjmsAdtMessage;
+import oracle.jms.AQjmsFactory;
+import oracle.jms.AQjmsSession;
+
+/**
+ * 对数据库的消息队列进行实时监听
+ * 
+ * @author sunyj
+ * @since 2016年7月7日 下午8:49:26
+ */
+@Service
+public class AQListener {
+
+	@Autowired
+	private IndexService indexService;
+
+	@Autowired
+	private QueueMessageParser queueMessageParser;
+
+	/**
+	 * 标志,判断是否已存在监听线程,防止重复开启监听线程
+	 */
+	private boolean listening = false;
+
+	Logger logger = Logger.getLogger(AQListener.class);
+
+	public void execute() {
+		if (listening) {
+			logger.warn("已存在线程正在实时监听!");
+			return;
+		}
+		listening = true;
+
+		logger.info("AQListener started...\n");
+		BasicDataSource dataSource = ContextUtils.getApplicationContext().getBean("dataSource",
+				org.apache.commons.dbcp.BasicDataSource.class);
+
+		try {
+			QueueConnectionFactory queueConnectionFactory = AQjmsFactory.getQueueConnectionFactory(dataSource.getUrl(),
+					new Properties());
+			QueueConnection connection = queueConnectionFactory.createQueueConnection(dataSource.getUsername(),
+					dataSource.getPassword());
+			AQjmsSession session = (AQjmsSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+			connection.start();
+
+			Queue queue = session.getQueue(dataSource.getUsername(), SearchConstants.LUCENE_QUEUE_NAME);
+			MessageConsumer consumer = session.createConsumer(queue, null, QueueMessageTypeFactory.getFactory(), null,
+					false);
+
+			// 添加监听器,队列中一旦有消息入队,就会接受该消息(并不是真的实时,一般会有10秒以内的延迟)
+			consumer.setMessageListener(new MessageListener() {
+				@Override
+				public void onMessage(Message message) {
+					AQjmsAdtMessage adtMessage = (AQjmsAdtMessage) message;
+					try {
+						QueueMessageTypeFactory payload = (QueueMessageTypeFactory) adtMessage.getAdtPayload();
+						// 对出队的消息进行解析、处理
+						process(payload.getMessage());
+					} catch (JMSException e) {
+						e.printStackTrace();
+					} catch (SQLException e) {
+						e.printStackTrace();
+					}
+				}
+			});
+		} catch (JMSException e) {
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * 对得到的队列消息进行解析,之后根据解析出来的对象,对lucene索引进行添加、更新或删除操作
+	 * 
+	 * @param message
+	 */
+	private void process(String message) {
+		ParsedQueueMessage parsedQueueMessage = null;
+		try {
+			parsedQueueMessage = queueMessageParser.parse(message);
+		} catch (JSONException e) {
+			e.printStackTrace();
+		}
+
+		if (parsedQueueMessage == null) {
+			logger.error("message parsing failed!");
+			return;
+		}
+
+		// 新增索引
+		if (parsedQueueMessage.isInsert()) {
+			indexService.save(parsedQueueMessage.getObject());
+		}
+		// 更新索引
+		else if (parsedQueueMessage.isUpdate()) {
+			indexService.update(parsedQueueMessage.getObject());
+		}
+		// 删除索引
+		else if (parsedQueueMessage.isDelete()) {
+			indexService.delete(parsedQueueMessage.getObject());
+		} else {
+			logger.error("message parsing failed!");
+		}
+	}
+}

+ 149 - 0
search-console/src/main/java/com/uas/search/console/jms/QueueMessageParser.java

@@ -0,0 +1,149 @@
+package com.uas.search.console.jms;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.alibaba.fastjson.JSONException;
+import com.alibaba.fastjson.JSONObject;
+import com.uas.search.console.dao.BrandSimpleInfoDao;
+import com.uas.search.console.dao.ComponentSimpleInfoDao;
+import com.uas.search.console.dao.KindSimpleInfoDao;
+import com.uas.search.console.model.BrandSimpleInfo;
+import com.uas.search.console.model.ComponentSimpleInfo;
+import com.uas.search.console.model.KindSimpleInfo;
+import com.uas.search.console.model.ParsedQueueMessage;
+import com.uas.search.console.util.SearchConstants;
+
+/**
+ * 对得到的队列消息进行解析的工具
+ * 
+ * @author sunyj
+ * @since 2016年7月7日 下午6:14:03
+ */
+@Service
+public class QueueMessageParser {
+
+	@Autowired
+	private KindSimpleInfoDao kindDao;
+
+	@Autowired
+	private BrandSimpleInfoDao brandDao;
+
+	@Autowired
+	private ComponentSimpleInfoDao componentDao;
+
+	/**
+	 * 对得到的json消息进行解析
+	 * 
+	 * @param message
+	 * @return ParsedQueueMessage对象
+	 * @throws JSONException
+	 */
+	// {"method":"value1","table":"value2","param1":"value3","param2":"value4"}
+	public ParsedQueueMessage parse(String message) throws JSONException {
+		if (StringUtils.isEmpty(message) || message.equals("{}")) {
+			return null;
+		}
+		ParsedQueueMessage parsedQueueMessage = new ParsedQueueMessage();
+		JSONObject jsonObject = JSONObject.parseObject(message);
+
+		// 解析数据库表的更改类型
+		String method = jsonObject.getString("method");
+		if (method.equals("insert")) {
+			parsedQueueMessage.setMethodType(ParsedQueueMessage.INSERT);
+		}
+
+		else if (method.equals("update")) {
+			parsedQueueMessage.setMethodType(ParsedQueueMessage.UPDATE);
+		}
+
+		else if (method.equals("delete")) {
+			parsedQueueMessage.setMethodType(ParsedQueueMessage.DELETE);
+		} else {
+			return null;
+		}
+
+		// 解析哪个表有更改
+		Object object = null;
+		String table = jsonObject.getString("table");
+		if (table.equals(SearchConstants.KIND_TABLE_NAME)) {
+			object = parseKind(jsonObject);
+		} else if (table.equals(SearchConstants.BRAND_TABLE_NAME)) {
+			object = parseBrand(jsonObject);
+		} else if (table.equals(SearchConstants.COMPONENT_TABLE_NAME)) {
+			object = parseComponent(jsonObject);
+		} else {
+			return null;
+		}
+
+		if (object == null) {
+			return null;
+		}
+
+		parsedQueueMessage.setObject(object);
+		return parsedQueueMessage;
+	}
+
+	/**
+	 * 对kind类目进行解析
+	 * 
+	 * @param jsonObject
+	 * @return kind类目对象
+	 * @throws JSONException
+	 */
+	// {"method":"value1","table":"product$kind","ki_id":5}
+	private KindSimpleInfo parseKind(JSONObject jsonObject) throws JSONException {
+		KindSimpleInfo kind = new KindSimpleInfo();
+		Long kindid = jsonObject.getLong("ki_id");
+		kind.setId(kindid);
+
+		KindSimpleInfo temp = kindDao.findById(kindid);
+		// 如果更改是删除的话,根据id获取到的对象为null
+		if (temp != null) {
+			kind = temp;
+		}
+		return kind;
+	}
+
+	/**
+	 * 对brand品牌进行解析
+	 * 
+	 * @param jsonObject
+	 * @return brand品牌对象
+	 * @throws JSONException
+	 */
+	// {"method":"value1","table":"product$brand","br_id":60}
+	private BrandSimpleInfo parseBrand(JSONObject jsonObject) throws JSONException {
+		BrandSimpleInfo brand = new BrandSimpleInfo();
+		Long brandid = jsonObject.getLong("br_id");
+		brand.setId(brandid);
+
+		BrandSimpleInfo temp = brandDao.findById(brandid);
+		if (temp != null) {
+			brand = temp;
+		}
+		return brand;
+	}
+
+	/**
+	 * 对component器件进行解析
+	 * 
+	 * @param jsonObject
+	 * @return component器件对象
+	 * @throws JSONException
+	 */
+	// {"method":"value1","table":"product$component","cmp_id":2029}
+	private ComponentSimpleInfo parseComponent(JSONObject jsonObject) throws JSONException {
+		ComponentSimpleInfo component = new ComponentSimpleInfo();
+		Long componentid = jsonObject.getLong("cmp_id");
+		component.setId(componentid);
+
+		ComponentSimpleInfo temp = componentDao.findById(componentid);
+		if (temp != null) {
+			component = temp;
+		}
+		return component;
+	}
+
+}

+ 58 - 0
search-console/src/main/java/com/uas/search/console/jms/QueueMessageTypeFactory.java

@@ -0,0 +1,58 @@
+package com.uas.search.console.jms;
+
+import java.sql.SQLException;
+
+import oracle.jdbc.OracleTypes;
+import oracle.jdbc.driver.OracleConnection;
+import oracle.jpub.runtime.MutableStruct;
+import oracle.sql.CustomDatum;
+import oracle.sql.CustomDatumFactory;
+import oracle.sql.Datum;
+import oracle.sql.STRUCT;
+
+/**
+ * 对数据库的数据格式进行转换
+ * 
+ * @author sunyj
+ * @since 2016年7月7日 下午8:49:44
+ */
+@SuppressWarnings("deprecation")
+public class QueueMessageTypeFactory implements CustomDatum, CustomDatumFactory {
+
+	public static final int SQL_TYPECODE = OracleTypes.STRUCT;
+
+	MutableStruct struct;
+
+	// 12表示字符串
+	static int[] sqlType = { 12 };
+	static CustomDatumFactory[] factory = new CustomDatumFactory[1];
+	static final QueueMessageTypeFactory messageFactory = new QueueMessageTypeFactory();
+
+	public QueueMessageTypeFactory() {
+		struct = new MutableStruct(new Object[1], sqlType, factory);
+	}
+
+	public static CustomDatumFactory getFactory() {
+		return messageFactory;
+	}
+
+	@Override
+	public CustomDatum create(Datum datum, int sqlType) throws SQLException {
+		if (datum == null) {
+			return null;
+		}
+		QueueMessageTypeFactory queueMessageType = new QueueMessageTypeFactory();
+		queueMessageType.struct = new MutableStruct((STRUCT) datum, QueueMessageTypeFactory.sqlType, factory);
+		return queueMessageType;
+	}
+
+	@Override
+	public Datum toDatum(OracleConnection connection) throws SQLException {
+		return struct.toDatum(connection, "QueueMessageTypeFactory");
+	}
+
+	public String getMessage() throws SQLException {
+		return (String) struct.getAttribute(0);
+	}
+
+}

+ 1 - 12
search-console/src/main/java/com/uas/search/console/model/BrandSimpleInfo.java

@@ -47,8 +47,6 @@ public class BrandSimpleInfo implements Serializable {
 	@Column(name = "br_name_en")
 	private String nameEn;
 
-	private String rowid;
-
 	public Long getId() {
 		return id;
 	}
@@ -81,18 +79,9 @@ public class BrandSimpleInfo implements Serializable {
 		this.nameEn = nameEn;
 	}
 
-	public String getRowid() {
-		return rowid;
-	}
-
-	public void setRowid(String rowid) {
-		this.rowid = rowid;
-	}
-
 	@Override
 	public String toString() {
-		return "BrandSimpleInfo [id=" + id + ", uuid=" + uuid + ", nameCn=" + nameCn + ", nameEn=" + nameEn + ", rowid="
-				+ rowid + "]";
+		return "BrandSimpleInfo [id=" + id + ", uuid=" + uuid + ", nameCn=" + nameCn + ", nameEn=" + nameEn + "]";
 	}
 
 }

+ 6 - 14
search-console/src/main/java/com/uas/search/console/model/ComponentSimpleInfo.java

@@ -10,6 +10,7 @@ import javax.persistence.FetchType;
 import javax.persistence.Id;
 import javax.persistence.JoinColumn;
 import javax.persistence.OneToMany;
+import javax.persistence.OrderBy;
 import javax.persistence.Table;
 
 /**
@@ -63,9 +64,8 @@ public class ComponentSimpleInfo implements Serializable {
 	 */
 	@OneToMany(cascade = { CascadeType.PERSIST, CascadeType.REMOVE }, fetch = FetchType.LAZY)
 	@JoinColumn(name = "pv_componentid")
-	private Set<PropertyValueSimpleInfo> properties;
-
-	private String rowid;
+	@OrderBy("detno")
+	private Set<PropertyValue> properties;
 
 	public Long getId() {
 		return id;
@@ -107,26 +107,18 @@ public class ComponentSimpleInfo implements Serializable {
 		this.brandid = brandid;
 	}
 
-	public Set<PropertyValueSimpleInfo> getProperties() {
+	public Set<PropertyValue> getProperties() {
 		return properties;
 	}
 
-	public void setProperties(Set<PropertyValueSimpleInfo> properties) {
+	public void setProperties(Set<PropertyValue> properties) {
 		this.properties = properties;
 	}
 
-	public String getRowid() {
-		return rowid;
-	}
-
-	public void setRowid(String rowid) {
-		this.rowid = rowid;
-	}
-
 	@Override
 	public String toString() {
 		return "ComponentSimpleInfo [id=" + id + ", uuid=" + uuid + ", code=" + code + ", kindid=" + kindid
-				+ ", brandid=" + brandid + ", properties=" + properties + ", rowid=" + rowid + "]";
+				+ ", brandid=" + brandid + ", properties=" + properties + "]";
 	}
 
 }

+ 1 - 12
search-console/src/main/java/com/uas/search/console/model/KindSimpleInfo.java

@@ -47,8 +47,6 @@ public class KindSimpleInfo implements Serializable {
 	@Column(name = "ki_isleaf")
 	private Short isLeaf;
 
-	private String rowid;
-
 	public Long getId() {
 		return id;
 	}
@@ -81,18 +79,9 @@ public class KindSimpleInfo implements Serializable {
 		this.isLeaf = isLeaf;
 	}
 
-	public String getRowid() {
-		return rowid;
-	}
-
-	public void setRowid(String rowid) {
-		this.rowid = rowid;
-	}
-
 	@Override
 	public String toString() {
-		return "KindSimpleInfo [id=" + id + ", nameCn=" + nameCn + ", level=" + level + ", isLeaf=" + isLeaf
-				+ ", rowid=" + rowid + "]";
+		return "KindSimpleInfo [id=" + id + ", nameCn=" + nameCn + ", level=" + level + ", isLeaf=" + isLeaf + "]";
 	}
 
 }

+ 84 - 0
search-console/src/main/java/com/uas/search/console/model/ParsedQueueMessage.java

@@ -0,0 +1,84 @@
+package com.uas.search.console.model;
+
+/**
+ * 对数据库队列里的消息进行解析后所得到的数据
+ * 
+ * @author sunyj
+ * @since 2016年7月7日 下午8:50:13
+ */
+public class ParsedQueueMessage {
+
+	/**
+	 * 数据库中表的改动为insert类型
+	 */
+	public static final int INSERT = 1;
+
+	/**
+	 * 改动为update类型
+	 */
+	public static final int UPDATE = 2;
+
+	/**
+	 * 改动为delete类型
+	 */
+	public static final int DELETE = 3;
+
+	/**
+	 * 表改动后,解析消息时,更改的类型
+	 */
+	private int methodType;
+
+	/**
+	 * 存放解析出来的对象:kind、brand或component对象
+	 */
+	private Object object;
+
+	/**
+	 * 是否为insert类型
+	 * 
+	 * @return
+	 */
+	public boolean isInsert() {
+		return methodType == INSERT;
+	}
+
+	/**
+	 * 是否为update类型
+	 * 
+	 * @return
+	 */
+	public boolean isUpdate() {
+		return methodType == UPDATE;
+	}
+
+	/**
+	 * 是否为delete类型
+	 * 
+	 * @return
+	 */
+	public boolean isDelete() {
+		return methodType == DELETE;
+	}
+
+	public int getMethodType() {
+		return methodType;
+	}
+
+	public void setMethodType(int methodType) {
+		this.methodType = methodType;
+	}
+
+	public Object getObject() {
+		return object;
+	}
+
+	public void setObject(Object object) {
+		this.object = object;
+	}
+
+	@Override
+	public String toString() {
+		return "ParsedQueueMessage [methodType=" + methodType + ", object=" + object + "]";
+	}
+
+}

+ 119 - 0
search-console/src/main/java/com/uas/search/console/model/PropertyValue.java

@@ -0,0 +1,119 @@
+package com.uas.search.console.model;
+
+import java.io.Serializable;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+
+/**
+ * 器件对应的属性的值
+ * 
+ * @author suntg
+ * @since 2016年3月11日下午2:24:29
+ */
+@Entity
+@Table(name = "product$propertyvalue")
+public class PropertyValue implements Serializable {
+
+	/**
+	 * 序列号
+	 */
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * id
+	 */
+	@Id
+	@Column(name = "pv_id")
+	private Long id;
+
+	/**
+	 * 器件Id
+	 */
+	@Column(name = "pv_componentid")
+	private Long componentid;
+
+	/**
+	 * 属性Id
+	 */
+	@Column(name = "pv_propertyid")
+	private Long propertyid;
+
+	/**
+	 * 属性
+	 */
+	@OneToOne(cascade = { CascadeType.REFRESH })
+	@JoinColumn(name = "pv_propertyid", insertable = false, updatable = false)
+	private Property property;
+
+	/**
+	 * 排序
+	 */
+	@Column(name = "pv_detno")
+	private Short detno;
+
+	/**
+	 * 属性的值
+	 */
+	@Column(name = "pv_value")
+	private String value;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Long getComponentid() {
+		return componentid;
+	}
+
+	public void setComponentid(Long componentid) {
+		this.componentid = componentid;
+	}
+
+	public Property getProperty() {
+		return property;
+	}
+
+	public void setProperty(Property property) {
+		this.property = property;
+	}
+
+	public Short getDetno() {
+		return detno;
+	}
+
+	public void setDetno(Short detno) {
+		this.detno = detno;
+	}
+
+	public String getValue() {
+		return value;
+	}
+
+	public void setValue(String value) {
+		this.value = value;
+	}
+
+	public Long getPropertyid() {
+		return propertyid;
+	}
+
+	public void setPropertyid(Long propertyid) {
+		this.propertyid = propertyid;
+	}
+
+	@Override
+	public String toString() {
+		return "PropertyValue [propertyid=" + propertyid + ", value=" + value + "]";
+	}
+
+}

+ 0 - 75
search-console/src/main/java/com/uas/search/console/model/PropertyValueSimpleInfo.java

@@ -1,75 +0,0 @@
-package com.uas.search.console.model;
-
-import java.io.Serializable;
-
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.Table;
-
-/**
- * 器件对应的属性的值
- * 
- * @author suntg
- * @since 2016年3月11日下午2:24:29
- */
-@Entity
-@Table(name = "product$propertyvalue")
-public class PropertyValueSimpleInfo implements Serializable {
-
-	/**
-	 * 序列号
-	 */
-	private static final long serialVersionUID = 1L;
-
-	/**
-	 * id
-	 */
-	@Id
-	@Column(name = "pv_id")
-	private Long id;
-
-	/**
-	 * 属性Id
-	 */
-	@Column(name = "pv_propertyid")
-	private Long propertyid;
-
-	/**
-	 * 属性的值
-	 */
-	@Column(name = "pv_value")
-	private String value;
-
-	private String rowid;
-
-	public String getValue() {
-		return value;
-	}
-
-	public void setValue(String value) {
-		this.value = value;
-	}
-
-	public Long getPropertyid() {
-		return propertyid;
-	}
-
-	public void setPropertyid(Long propertyid) {
-		this.propertyid = propertyid;
-	}
-
-	public String getRowid() {
-		return rowid;
-	}
-
-	public void setRowid(String rowid) {
-		this.rowid = rowid;
-	}
-
-	@Override
-	public String toString() {
-		return "PropertyValue [propertyid=" + propertyid + ", value=" + value + ", rowid=" + rowid + "]";
-	}
-
-}

+ 2 - 13
search-console/src/main/java/com/uas/search/console/service/IndexService.java

@@ -9,22 +9,11 @@ package com.uas.search.console.service;
 public interface IndexService {
 
 	/**
-	 * 创建索引
+	 * 初始化时,从数据库中得到全部类目、品牌和器件对象,写进索引中
 	 * 
-	 * @param fromDB
-	 *            器件数据的来源是否为数据库,为1表示从数据库获取,为null或其他值表示从本地文件获取
 	 * @return 创建的索引花费总时间 ms
 	 */
-	public Long createIndexes(Integer fromDB);
-
-	/**
-	 * 下载component数据至本地
-	 * 
-	 * @param startFileIndex
-	 *            从第startFileIndex(从1开始)个文件继续下载
-	 * @return component记录的数目
-	 */
-	public Long downloadComponentData(Integer startFileIndex);
+	public Long createIndexs();
 
 	/**
 	 * 将新对象添加在lucene索引中

+ 53 - 174
search-console/src/main/java/com/uas/search/console/service/impl/IndexServiceImpl.java

@@ -5,10 +5,8 @@ import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.IOException;
-import java.io.PrintWriter;
 import java.nio.file.Paths;
 import java.util.Date;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
@@ -35,9 +33,10 @@ import com.uas.search.console.dao.KindSimpleInfoDao;
 import com.uas.search.console.model.BrandSimpleInfo;
 import com.uas.search.console.model.ComponentSimpleInfo;
 import com.uas.search.console.model.KindSimpleInfo;
-import com.uas.search.console.model.PropertyValueSimpleInfo;
+import com.uas.search.console.model.PropertyValue;
 import com.uas.search.console.service.IndexService;
 import com.uas.search.console.support.IndexWriterManager;
+import com.uas.search.console.util.MergeComponentData;
 import com.uas.search.console.util.SearchConstants;
 
 /**
@@ -64,13 +63,9 @@ public class IndexServiceImpl implements IndexService {
 
 	private FSDirectory directory;
 
-	private Logger logger = Logger.getLogger(IndexServiceImpl.class);
-
-	// 分页获取component数据时的页的大小
 	private static final int PAGE_SIZE = 1000;
 
-	// 单个文件存储的最大数据数目
-	public static final int SINGLE_FILE_MAX_SIZE = 100000;
+	private Logger logger = Logger.getLogger(IndexServiceImpl.class);
 
 	public IndexServiceImpl() {
 		try {
@@ -82,7 +77,7 @@ public class IndexServiceImpl implements IndexService {
 	}
 
 	@Override
-	public Long createIndexes(Integer fromDB) {
+	public Long createIndexs() {
 		try {
 			if (IndexWriter.isLocked(directory)) {
 				logger.warn("已有线程正在创建索引!");
@@ -95,27 +90,22 @@ public class IndexServiceImpl implements IndexService {
 		// 清除旧索引
 		File file = new File(SearchConstants.INDEX_DIR);
 		if (file.isDirectory()) {
-			clearDir(file);
+			deleteOldIndex(file);
 		}
 
 		try {
 			indexWriter = indexWriterManager.get();
 			Long startTime = new Date().getTime();
 
-			Long kindSize = createKindIndexes();
+			Long kindSize = createKindIndexs();
 			Long kindTime = new Date().getTime();
 			logger.info("创建类目索引: " + kindSize + "条,耗时 " + (kindTime - startTime) + " ms\n");
 
-			Long brandSize = createBrandIndexes();
+			Long brandSize = createBrandIndexs();
 			Long brandTime = new Date().getTime();
 			logger.info("创建品牌索引: " + brandSize + "条,耗时 " + (brandTime - kindTime) + " ms\n");
 
-			Long componentSize = 0L;
-			if (fromDB != null && fromDB == 1) {
-				componentSize = createComponentIndexesFromDatabase();
-			} else {
-				componentSize = createComponentIndexesFromFiles();
-			}
+			Long componentSize = createComponentIndexesWithFiles();
 			Long componentTime = new Date().getTime();
 			logger.info("创建器件索引: " + componentSize + "条,耗时 " + (componentTime - brandTime) + " ms\n");
 
@@ -139,7 +129,7 @@ public class IndexServiceImpl implements IndexService {
 	 * @return 写入的类目索引数
 	 * @throws IOException
 	 */
-	private Long createKindIndexes() throws IOException {
+	private Long createKindIndexs() throws IOException {
 		logger.info("正在创建类目索引...");
 		List<KindSimpleInfo> kinds = kindDao.findAll();
 
@@ -161,7 +151,7 @@ public class IndexServiceImpl implements IndexService {
 	 * @return 写入的品牌索引数
 	 * @throws IOException
 	 */
-	private Long createBrandIndexes() throws IOException {
+	private Long createBrandIndexs() throws IOException {
 		logger.info("正在创建品牌索引...");
 		List<BrandSimpleInfo> brands = brandDao.findAll();
 		if (CollectionUtils.isEmpty(brands))
@@ -177,23 +167,18 @@ public class IndexServiceImpl implements IndexService {
 		return (long) brands.size();
 	}
 
-	/**
-	 * 从本地文件获取器件数据
-	 * 
-	 * @return
-	 */
-	private Long createComponentIndexesFromFiles() {
+	private Long createComponentIndexesWithFiles() {
 		logger.info("正在创建器件索引...");
 		Long size = 0L;
 		try {
 			// 从本地路径读取器件数据
-			File[] files = new File(SearchConstants.COMPONENT_DATA_DIR).listFiles();
+			File[] files = new File(SearchConstants.COMPONENT_WITH_PROPERTY_DIR).listFiles();
 			if (files == null || files.length == 0) {
 				logger.info("创建器件索引失败,原因:器件数据文件不存在!");
 				return 0L;
 			}
 			// 将要创建的索引总数目约为:文件数目*单个文件的行数
-			long totalSize = files.length * SINGLE_FILE_MAX_SIZE;
+			long totalSize = files.length * MergeComponentData.SINGLE_FILE_MAX_SIZE;
 			for (File file : files) {
 				logger.info("读取文件: " + file.getName());
 				BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
@@ -205,8 +190,7 @@ public class IndexServiceImpl implements IndexService {
 						size++;
 						// 每创建10000条,打印一次进度
 						if (size % 10000 == 0) {
-							logger.info(
-									String.format("Component indexed...............%.2f%%", size * 100.0 / totalSize));
+							System.out.printf("Component indexed...................%.2f%%\n", size * 100.0 / totalSize);
 						}
 						indexWriter.addDocument(document);
 					}
@@ -223,108 +207,13 @@ public class IndexServiceImpl implements IndexService {
 		return size;
 	}
 
-	@Override
-	public Long downloadComponentData(Integer startFileIndex) {
-		logger.info("正在下载器件数据...");
-
-		// 清空data文件夹
-		File dataDir = new File(SearchConstants.COMPONENT_DATA_DIR);
-		// 若startFileIndex无意义,全部重新下载
-		if (startFileIndex == null || startFileIndex < 1) {
-			if (dataDir.isDirectory()) {
-				clearDir(dataDir);
-			}
-		}
-		if (!dataDir.exists()) {
-			dataDir.mkdir();
-		}
-
-		Long size = 0L;
-		PageParams params = new PageParams();
-		int page = 1;
-		// 重新计算开始的页码
-		if (startFileIndex != null && startFileIndex >= 1) {
-			page = SINGLE_FILE_MAX_SIZE / PAGE_SIZE * (startFileIndex - 1) + 1;
-		}
-		params.setCount(PAGE_SIZE);
-		params.setPage(page);
-
-		// 分页获取component数据
-		PageInfo info = new PageInfo(params);
-		Page<ComponentSimpleInfo> pageResult = componentDao.findAll(info);
-		long totalElements = pageResult.getTotalElements();
-		int fileIndex = 1;
-		// 重新计算已下载的数据大小
-		if (startFileIndex != null && startFileIndex >= 1) {
-			size = Math.min(SINGLE_FILE_MAX_SIZE * (startFileIndex - 1), totalElements);
-			fileIndex = startFileIndex;
-		}
-		logger.info("Number of components: " + totalElements);
-
-		PrintWriter printWriter = null;
-		try {
-			String dataFilePath = SearchConstants.COMPONENT_DATA_DIR + "component_" + fileIndex + ".json";
-			if(totalElements > size){
-				printWriter = new PrintWriter(dataFilePath);
-				logger.info("Writing data into " + dataFilePath);
-			}
-			int dataCount = 0;
-			while (totalElements > size) {
-				// 一个文件存放SINGLE_FILE_MAX_SIZE条数据,一旦超过,写入新的文件
-				if (dataCount >= SINGLE_FILE_MAX_SIZE) {
-					printWriter.flush();
-					printWriter.close();
-					dataCount = 0;
-					dataFilePath = SearchConstants.COMPONENT_DATA_DIR + "component_" + (++fileIndex) + ".json";
-					printWriter = new PrintWriter(dataFilePath);
-					logger.info("Writing data into " + dataFilePath);
-				}
-
-				// 获取数据并写入文件
-				List<ComponentSimpleInfo> components = pageResult.getContent();
-				for (ComponentSimpleInfo component : components) {
-					// 属性值的value为空,不写入索引
-					Set<PropertyValueSimpleInfo> properties = component.getProperties();
-					Set<PropertyValueSimpleInfo> removingProperties = new HashSet<>();
-					for (PropertyValueSimpleInfo property : properties) {
-						if (StringUtils.isEmpty(property.getValue())) {
-							removingProperties.add(property);
-						}
-					}
-					properties.removeAll(removingProperties);
-					component.setProperties(properties);
-					printWriter.println(JSONObject.toJSONString(component));
-				}
-				size += components.size();
-				dataCount += components.size();
-
-				// 打印器件数据的下载进度(百分比)
-				if (size % 10000 == 0) {
-					logger.info(String.format("Downloading...............%.2f%%", (size * 100.0 / totalElements)));
-				}
-
-				page++;
-				params.setPage(page);
-				info = new PageInfo(params);
-				pageResult = componentDao.findAll(info);
-			}
-		} catch (FileNotFoundException e) {
-			e.printStackTrace();
-		} finally {
-			if (printWriter != null) {
-				printWriter.close();
-			}
-		}
-		return size;
-	}
-
 	/**
 	 * 创建器件索引,从数据库取数据
 	 * 
 	 * @return 写入的器件索引数
 	 * @throws IOException
 	 */
-	private Long createComponentIndexesFromDatabase() throws IOException {
+	public Long createComponentIndexs() throws IOException {
 		logger.info("正在创建器件索引...");
 		Long size = 0L;
 		PageParams params = new PageParams();
@@ -350,9 +239,9 @@ public class IndexServiceImpl implements IndexService {
 
 			// 器件索引的创建进度(百分比)
 			double indexProgress = size * 100.0 / totalElements;
-			// 每创建0.3%,提交一次,避免内存耗尽,发生OutOfMemoryError
-			if (indexProgress - recordProgress > 0.3) {
-				logger.info(String.format("Component indexed...............%.2f%%", indexProgress));
+			System.out.printf("Component indexed...................%.2f%%\n", indexProgress);
+			// 每创建5%,提交一次,避免内存耗尽,发生OutOfMemoryError
+			if (indexProgress - recordProgress > 5) {
 				indexWriter.commit();
 				recordProgress = indexProgress;
 			}
@@ -374,15 +263,16 @@ public class IndexServiceImpl implements IndexService {
 	 */
 	private Document toDocument(KindSimpleInfo kind) {
 		if (kind == null || kind.getId() == null || StringUtils.isEmpty(kind.getNameCn()) || kind.getIsLeaf() == null
-				|| kind.getLevel() == null || StringUtils.isEmpty(kind.getRowid())) {
+				|| kind.getLevel() == null) {
 			return null;
 		}
 		Document document = new Document();
+		// 不能用LongField,否则后续实时更新索引时,方法updateDocument(new Term("", ""),
+		// doc)无法根据id进行更新
 		document.add(new StringField(SearchConstants.KIND_ID_FIELD, String.valueOf(kind.getId()), Store.YES));
 		document.add(new TextField(SearchConstants.KIND_NAMECN_FIELD, kind.getNameCn(), Store.YES));
 		document.add(new StringField(SearchConstants.KIND_ISLEAF_FIELD, String.valueOf(kind.getIsLeaf()), Store.YES));
 		document.add(new StringField(SearchConstants.KIND_LEVEL_FIELD, String.valueOf(kind.getLevel()), Store.YES));
-		document.add(new StringField(SearchConstants.KIND_ROWID_FIELD, kind.getRowid(), Store.YES));
 		return document;
 	}
 
@@ -394,18 +284,20 @@ public class IndexServiceImpl implements IndexService {
 	 */
 	private Document toDocument(BrandSimpleInfo brand) {
 		if (brand == null || brand.getId() == null || StringUtils.isEmpty(brand.getNameCn())
-				|| StringUtils.isEmpty(brand.getUuid()) || StringUtils.isEmpty(brand.getRowid())) {
+				|| StringUtils.isEmpty(brand.getUuid())) {
 			return null;
 		}
 		Document document = new Document();
 		document.add(new StringField(SearchConstants.BRAND_ID_FIELD, String.valueOf(brand.getId()), Store.YES));
-		document.add(new TextField(SearchConstants.BRAND_NAMECN_FIELD, brand.getNameCn(), Store.YES));
+		String nameCn = brand.getNameCn();
+		if (!StringUtils.isEmpty(nameCn)) {
+			document.add(new TextField(SearchConstants.BRAND_NAMECN_FIELD, nameCn, Store.YES));
+		}
 		String nameEn = brand.getNameEn();
 		if (!StringUtils.isEmpty(nameEn)) {
 			document.add(new TextField(SearchConstants.BRAND_NAMEEN_FIELD, nameEn, Store.YES));
 		}
 		document.add(new StringField(SearchConstants.BRAND_UUID_FIELD, brand.getUuid(), Store.YES));
-		document.add(new StringField(SearchConstants.BRAND_ROWID_FIELD, brand.getRowid(), Store.YES));
 		return document;
 	}
 
@@ -418,7 +310,7 @@ public class IndexServiceImpl implements IndexService {
 	private Document toDocument(ComponentSimpleInfo component) {
 		if (component == null || component.getId() == null || StringUtils.isEmpty(component.getUuid())
 				|| StringUtils.isEmpty(component.getCode()) || component.getKindid() == null
-				|| component.getBrandid() == null || StringUtils.isEmpty(component.getRowid())) {
+				|| component.getBrandid() == null) {
 			return null;
 		}
 		Document document = new Document();
@@ -431,21 +323,11 @@ public class IndexServiceImpl implements IndexService {
 				Store.YES));
 		document.add(new StringField(SearchConstants.COMPONENT_BRANDID_FIELD, String.valueOf(component.getBrandid()),
 				Store.YES));
-		document.add(new StringField(SearchConstants.COMPONENT_ROWID_FIELD, component.getRowid(), Store.YES));
 
 		// 属性值加入索引,索引中field的键:"pr_"前缀连接属性的id
-		Set<PropertyValueSimpleInfo> propertyValues = component.getProperties();
-		StringBuilder stringBuilder = new StringBuilder();
-		for (PropertyValueSimpleInfo propertyValue : propertyValues) {
+		Set<PropertyValue> propertyValues = component.getProperties();
+		for (PropertyValue propertyValue : propertyValues) {
 			if (!StringUtils.isEmpty(propertyValue.getValue())) {
-				/*
-				 * 将属性值每行记录的rowid拼接在一起建立索引, 用于实时更新索引服务中 (属性值记录被删除时,
-				 * 无法根据DCN返回的属性值记录的rowid,得知需要更新哪个器件的索引),
-				 * 通过该rowid,从本地索引中获得相应器件的rowid, 再根据该rowid从数据库中获取器件信息, 更新本地索引
-				 */
-				// 将rowid中的符号+和空格替换为_,并以空格将rowid隔开
-				stringBuilder.append(propertyValue.getRowid().replaceAll("[ +]+", "_")).append(" ");
-
 				String fieldKey = SearchConstants.COMPONENT_PROPERTY_PREFIX + propertyValue.getPropertyid();
 				document.add(new StringField(fieldKey, propertyValue.getValue(), Store.YES));
 
@@ -454,31 +336,28 @@ public class IndexServiceImpl implements IndexService {
 				document.add(new TextField(fieldKeyTokenized, propertyValue.getValue(), Store.YES));
 			}
 		}
-		if (!StringUtils.isEmpty(stringBuilder.toString())) {
-			document.add(new TextField(SearchConstants.COMPONENT_PROPERTY_ROWIDS_FIELD, stringBuilder.toString(),
-					Store.YES));
-		}
 		return document;
 	}
 
 	/**
-	 * 清空文件夹
+	 * 删除原有索引文件
 	 * 
-	 * @param dir
+	 * @param file
 	 */
-	private void clearDir(File dir) {
-		if (dir == null) {
+	private void deleteOldIndex(File file) {
+		if (file == null) {
 			return;
 		}
-		if (dir.isDirectory()) {
-			File[] files = dir.listFiles();
+		if (file.isDirectory()) {
+			File[] files = file.listFiles();
 			for (File f : files) {
-				clearDir(f);
+				deleteOldIndex(f);
 			}
 		}
-		dir.delete();
+
+		file.delete();
 		try {
-			logger.info("Deleted " + dir.getCanonicalPath());
+			logger.info("deleted " + file.getCanonicalPath());
 		} catch (IOException e) {
 			e.printStackTrace();
 		}
@@ -487,9 +366,9 @@ public class IndexServiceImpl implements IndexService {
 	@Override
 	public void save(Object obj) {
 		if (obj == null) {
-			logger.error("实时更新对象为空");
 			return;
 		}
+
 		try {
 			indexWriter = indexWriterManager.get();
 			if (obj instanceof KindSimpleInfo) {
@@ -518,13 +397,12 @@ public class IndexServiceImpl implements IndexService {
 		} finally {
 			indexWriterManager.release();
 		}
-		logger.info("Saved object... " + obj + "\n");
+		logger.info("saved object... " + obj + "\n");
 	}
 
 	@Override
 	public void update(Object obj) {
 		if (obj == null) {
-			logger.error("实时更新对象为空");
 			return;
 		}
 		try {
@@ -533,20 +411,22 @@ public class IndexServiceImpl implements IndexService {
 				KindSimpleInfo kind = (KindSimpleInfo) obj;
 				Document document = toDocument(kind);
 				if (document != null) {
-					indexWriter.updateDocument(new Term(SearchConstants.KIND_ROWID_FIELD, kind.getRowid()), document);
+					indexWriter.updateDocument(new Term(SearchConstants.KIND_ID_FIELD, String.valueOf(kind.getId())),
+							document);
 				}
 			} else if (obj instanceof BrandSimpleInfo) {
 				BrandSimpleInfo brand = (BrandSimpleInfo) obj;
 				Document document = toDocument((BrandSimpleInfo) obj);
 				if (document != null) {
-					indexWriter.updateDocument(new Term(SearchConstants.BRAND_ROWID_FIELD, brand.getRowid()), document);
+					indexWriter.updateDocument(new Term(SearchConstants.BRAND_ID_FIELD, String.valueOf(brand.getId())),
+							document);
 				}
 			} else if (obj instanceof ComponentSimpleInfo) {
 				ComponentSimpleInfo component = (ComponentSimpleInfo) obj;
 				Document document = toDocument(component);
 				if (document != null) {
-					indexWriter.updateDocument(new Term(SearchConstants.COMPONENT_ROWID_FIELD, component.getRowid()),
-							document);
+					indexWriter.updateDocument(
+							new Term(SearchConstants.COMPONENT_ID_FIELD, String.valueOf(component.getId())), document);
 				}
 			} else {
 				logger.error("message parsing failed!");
@@ -559,26 +439,25 @@ public class IndexServiceImpl implements IndexService {
 		} finally {
 			indexWriterManager.release();
 		}
-		logger.info("Updated object... " + obj + "\n");
+		logger.info("updated object... " + obj + "\n");
 	}
 
 	@Override
 	public void delete(Object obj) {
 		if (obj == null) {
-			logger.error("实时更新对象为空");
 			return;
 		}
 		try {
 			indexWriter = indexWriterManager.get();
 			if (obj instanceof KindSimpleInfo) {
-				indexWriter
-						.deleteDocuments(new Term(SearchConstants.KIND_ROWID_FIELD, ((KindSimpleInfo) obj).getRowid()));
+				indexWriter.deleteDocuments(
+						new Term(SearchConstants.KIND_ID_FIELD, ((KindSimpleInfo) obj).getId().toString()));
 			} else if (obj instanceof BrandSimpleInfo) {
 				indexWriter.deleteDocuments(
-						new Term(SearchConstants.BRAND_ROWID_FIELD, ((BrandSimpleInfo) obj).getRowid()));
+						new Term(SearchConstants.BRAND_ID_FIELD, ((BrandSimpleInfo) obj).getId().toString()));
 			} else if (obj instanceof ComponentSimpleInfo) {
 				indexWriter.deleteDocuments(
-						new Term(SearchConstants.COMPONENT_ROWID_FIELD, ((ComponentSimpleInfo) obj).getRowid()));
+						new Term(SearchConstants.COMPONENT_ID_FIELD, ((ComponentSimpleInfo) obj).getId().toString()));
 			} else {
 				logger.error("message parsing failed!");
 			}
@@ -590,6 +469,6 @@ public class IndexServiceImpl implements IndexService {
 		} finally {
 			indexWriterManager.release();
 		}
-		logger.info("Deleted object... " + obj + "\n");
+		logger.info("deleted object... " + obj + "\n");
 	}
 }

+ 0 - 39
search-console/src/main/java/com/uas/search/console/service/impl/SearchServiceImpl.java

@@ -885,45 +885,6 @@ public class SearchServiceImpl implements SearchService {
 		return booleanQuery;
 	}
 
-	@Override
-	public String getComponentRowidByPropertyValueRowid(String rowid) {
-		String message = "";
-		if (isKeywordInvalid(rowid)) {
-			message = "输入无效:" + rowid;
-			logger.error(message);
-			throw new SystemError(message);
-		}
-		searcherManager.maybeReopen();
-		IndexSearcher indexSearcher = searcherManager.get();
-		if (indexSearcher == null) {
-			message = "获取索引文件失败";
-			logger.error(message);
-			throw new SystemError(message);
-		}
-
-		try {
-			rowid = rowid.replaceAll("[ +]+", "_");
-			BooleanQuery booleanQuery = getBooleanQuery(SearchConstants.COMPONENT_PROPERTY_ROWIDS_FIELD, rowid);
-			logger.info(booleanQuery);
-			TopDocs topDocs = indexSearcher.search(booleanQuery, TOP_NUM);
-			for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
-				Document document = indexSearcher.doc(scoreDoc.doc);
-				String propertyRowids = document.get(SearchConstants.COMPONENT_PROPERTY_ROWIDS_FIELD);
-				// 因分词后,不区分大小写,可能会匹配到很多结果
-				if (propertyRowids.contains(rowid)) {
-					return document.get(SearchConstants.COMPONENT_ROWID_FIELD);
-				}
-			}
-			logger.error(
-					"属性值rowid为 " + rowid + " 匹配(不区分大小写的情况下)到的器件数量为: totalHits " + topDocs.totalHits + ", 但未找到完全匹配的器件");
-		} catch (NumberFormatException e) {
-			e.printStackTrace();
-		} catch (IOException e) {
-			e.printStackTrace();
-		}
-		return null;
-	}
-
 	/**
 	 * 判断搜索词是否为无效的(比如只包含特殊字符,不含有任何字母、数字、汉字等有意义的字符)
 	 * 

+ 0 - 37
search-console/src/main/java/com/uas/search/console/support/ContextRefreshedProcessor.java

@@ -1,37 +0,0 @@
-package com.uas.search.console.support;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.ApplicationListener;
-import org.springframework.context.event.ContextRefreshedEvent;
-
-import com.uas.search.console.dcn.DCNRegistrationManager;
-
-/**
- * 容器启动之后执行
- * 
- * @author sunyj
- * @since 2016年9月17日 下午8:58:42
- */
-public class ContextRefreshedProcessor implements ApplicationListener<ContextRefreshedEvent> {
-
-	@Autowired
-	private SysConf sysConf;
-
-	@Autowired
-	private DCNRegistrationManager dcnRegistrationManager;
-
-	@Override
-	public void onApplicationEvent(ContextRefreshedEvent event) {
-		// 事件会发生两次:
-		// 1.Initializing Spring root WebApplicationContext;
-		// 2.Initializing Spring FrameworkServlet 'spring-mvc-dispatcher'
-		// 2的情况下log4j刚初始化完成,此时注册DCN
-		if (event.getApplicationContext().getParent() != null) {
-			if (sysConf.getRegisterDCN()) {
-				dcnRegistrationManager.registerDataChangeNotification();
-			}
-		}
-
-	}
-
-}

+ 0 - 24
search-console/src/main/java/com/uas/search/console/support/SysConf.java

@@ -1,24 +0,0 @@
-package com.uas.search.console.support;
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-
-/**
- * 系统运行参数,通过属性文件注入
- * 
- * @author sunyj
- * @since 2016年9月17日 下午9:02:28
- */
-@Component
-public class SysConf {
-	@Value("#{sys.registerDCN}")
-	private Boolean registerDCN;
-
-	public Boolean getRegisterDCN() {
-		return registerDCN;
-	}
-
-	public void setRegisterDCN(Boolean registerDCN) {
-		this.registerDCN = registerDCN;
-	}
-}

+ 165 - 0
search-console/src/main/java/com/uas/search/console/util/MergeComponentData.java

@@ -0,0 +1,165 @@
+package com.uas.search.console.util;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.springframework.util.StringUtils;
+
+import com.alibaba.fastjson.JSONObject;
+import com.uas.search.console.model.ComponentSimpleInfo;
+import com.uas.search.console.model.PropertyValue;
+
+/**
+ * 用于对从数据库导出的器件和属性值两个文本文件进行处理,将每个器件所拥有的属性值提取出来,之后每个器件作为一行,以json的形式写入多个文件中
+ * 
+ * @author sunyj
+ * @since 2016年8月8日 下午9:00:31
+ */
+public class MergeComponentData {
+
+	// 单个文件存储的最大数据数目
+	public static final int SINGLE_FILE_MAX_SIZE = 100000;
+
+	// 器件和属性值两个文本文件的路径
+	private static final String DATA_DIR = "C:\\Users\\sunyj-pc\\Desktop\\data\\prod";
+
+	/**
+	 * 将从本地文件读取的一行字符串数据解析为器件对象
+	 * 
+	 * @param data
+	 *            格式为"CMP_ID" "CMP_BRID" "CMP_CODE" "CMP_KIID" "CMP_UUID",如1 149
+	 *            "10120-5212PC" 295 "2502600600000001"
+	 * @return
+	 */
+	private static ComponentSimpleInfo parseComponent(String data) {
+		ComponentSimpleInfo component = new ComponentSimpleInfo();
+		String[] strs = data.split("\t");
+		component.setId(Long.parseLong(strs[0]));
+		component.setBrandid(Long.parseLong(strs[1]));
+		component.setCode(strs[2].substring(1, strs[2].length() - 1));
+		component.setKindid(Long.parseLong(strs[3]));
+		component.setUuid(strs[4].substring(1, strs[4].length() - 1));
+		return component;
+	}
+
+	/**
+	 * 将从本地文件读取的一行字符串数据解析为属性值对象
+	 * 
+	 * @param data
+	 *            格式为"PV_COMPONENTID" "PV_PROPERTYID" "PV_VALUE",如1 394
+	 *            "Copper Alloy"
+	 * @return
+	 */
+	private static PropertyValue parsePropertyValue(String data) {
+		PropertyValue propertyValue = new PropertyValue();
+		String[] strs = data.split("\t");
+		propertyValue.setComponentid(Long.parseLong(strs[0]));
+		propertyValue.setPropertyid(Long.parseLong(strs[1]));
+		propertyValue.setValue(strs[2].substring(1, strs[2].length() - 1));
+		return propertyValue;
+	}
+
+	public static void merge() {
+		BufferedReader componentReader = null;
+		BufferedReader propertyValueReader = null;
+		PrintWriter printWriter = null;
+		// 分成多个文件存储
+		int fileIndex = 1;
+		try {
+			File file = new File(DATA_DIR + "\\components");
+			if (!file.exists()) {
+				file.mkdirs();
+			}
+			componentReader = new BufferedReader(new FileReader(DATA_DIR + "\\Component.txt"));
+			propertyValueReader = new BufferedReader(new FileReader(DATA_DIR + "\\PropertyValue.txt"));
+			printWriter = new PrintWriter(DATA_DIR + "\\components\\ComponentWithProperty_" + fileIndex + ".txt");
+			// 第一行内容为列名,不做解析
+			componentReader.readLine();
+			propertyValueReader.readLine();
+			String componentLine = null;
+			String propertyValueLine = null;
+			PropertyValue propertyValue = null;
+			int dataCount = 0;
+			while (!StringUtils.isEmpty(componentLine = componentReader.readLine())) {
+				dataCount++;
+				System.out.println(dataCount);
+				// 一个文件存放100000条数据,一旦超过,写入新的文件
+				if (dataCount > SINGLE_FILE_MAX_SIZE) {
+					System.out.println("--------------------------------new file");
+					dataCount = 1;
+					printWriter.flush();
+					printWriter.close();
+					fileIndex++;
+					printWriter = new PrintWriter(
+							DATA_DIR + "\\components\\ComponentWithProperty_" + fileIndex + ".txt");
+				}
+
+				ComponentSimpleInfo component = parseComponent(componentLine);
+				Set<PropertyValue> properties = new HashSet<>();
+				if (propertyValue == null && !StringUtils.isEmpty(propertyValueLine = propertyValueReader.readLine())) {
+					propertyValue = parsePropertyValue(propertyValueLine);
+				}
+				while (propertyValue.getComponentid().equals(component.getId())) {
+					propertyValue.setComponentid(null);
+					properties.add(propertyValue);
+					// 读到文件最后一行
+					if (StringUtils.isEmpty(propertyValueLine = propertyValueReader.readLine())) {
+						break;
+					}
+					propertyValue = parsePropertyValue(propertyValueLine);
+				}
+				component.setProperties(properties);
+				System.out.println(component);
+				printWriter.println(JSONObject.toJSONString(component));
+			}
+			printWriter.flush();
+		} catch (FileNotFoundException e) {
+			e.printStackTrace();
+		} catch (IOException e) {
+			e.printStackTrace();
+		} finally {
+			try {
+				componentReader.close();
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+			try {
+				propertyValueReader.close();
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+			printWriter.close();
+		}
+	}
+
+	public static void readData() {
+		BufferedReader br = null;
+		try {
+			br = new BufferedReader(new FileReader(DATA_DIR + "\\components\\ComponentWithProperty_1.txt"));
+			String line = br.readLine();
+			System.out.println(JSONObject.parseObject(line, ComponentSimpleInfo.class));
+		} catch (FileNotFoundException e) {
+			System.out.println("File not found!");
+		} catch (IOException e) {
+			e.printStackTrace();
+		} finally {
+			try {
+				br.close();
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+		}
+	}
+
+	public static void main(String[] args) {
+		merge();
+		// readData();
+	}
+
+}

+ 3 - 17
search-console/src/main/java/com/uas/search/console/util/SearchConstants.java

@@ -1,7 +1,5 @@
 package com.uas.search.console.util;
 
-import java.io.File;
-
 import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.analysis.standard.StandardAnalyzer;
 import org.wltea.analyzer.lucene.IKAnalyzer;
@@ -50,20 +48,15 @@ public class SearchConstants {
 	 */
 	public static final String COMPONENT_TABLE_NAME = "product$component";
 
-	/**
-	 * 属性值表明
-	 */
-	public static final String PROPERTYVALUE_TABLE_NAME = "product$propertyvalue";
-
 	/**
 	 * 索引文件存储路径
 	 */
-	public static final String INDEX_DIR = PathUtils.getFilePath() + "indexes" + File.separator;
+	public static final String INDEX_DIR = PathUtils.getFilePath() + "indexes";
 
 	/**
-	 * 该文件夹下存放器件数据,用于创建索引
+	 * 存放带有属性的器件数据的文件,用于创建索引
 	 */
-	public static final String COMPONENT_DATA_DIR = PathUtils.getFilePath() + "data" + File.separator;
+	public static final String COMPONENT_WITH_PROPERTY_DIR = PathUtils.getFilePath() + "components";
 
 	/**
 	 * 各索引字段的字符标示
@@ -72,14 +65,12 @@ public class SearchConstants {
 	public static final String KIND_NAMECN_FIELD = "ki_name_cn";
 	public static final String KIND_LEVEL_FIELD = "ki_level";
 	public static final String KIND_ISLEAF_FIELD = "ki_isleaf";
-	public static final String KIND_ROWID_FIELD = "ki_rowid";
 
 	public static final String BRAND_ID_FIELD = "br_id";
 	public static final String BRAND_NAMECN_FIELD = "br_name_cn";
 	public static final String BRAND_NAMEEN_FIELD = "br_name_en";
 	public static final String BRAND_UUID_FIELD = "br_uuid";
 	public static final String BRAND_WEIGHT_FIELD = "br_weight";
-	public static final String BRAND_ROWID_FIELD = "br_rowid";
 
 	public static final String COMPONENT_ID_FIELD = "cmp_id";
 	public static final String COMPONENT_UUID_FIELD = "cmp_uuid";
@@ -90,7 +81,6 @@ public class SearchConstants {
 	public static final String COMPONENT_BRANDID_FIELD = "cmp_brand_id";
 	public static final String COMPONENT_BRANDUUID_FIELD = "cmp_brand_uuid";
 	public static final String COMPONENT_BRANDNAME_FIELD = "cmp_brand_name_cn";
-	public static final String COMPONENT_ROWID_FIELD = "cmp_rowid";
 	/**
 	 * 创建器件属性的索引时,在属性id的前面添加该前缀作为Field的键
 	 */
@@ -99,9 +89,5 @@ public class SearchConstants {
 	 * 另外创建的经过分词的属性值,添加后缀作为Field的键
 	 */
 	public static final String COMPONENT_PROPERTY_TOKENIZED_SUFFIX = "_tokenized";
-	/**
-	 * 所有属性值的rowid用 ',' 连接在一起,建立索引
-	 */
-	public static final String COMPONENT_PROPERTY_ROWIDS_FIELD = "cmp_pr_rowids";
 
 }

+ 0 - 1
search-console/src/main/resources/dev/sys.properties

@@ -1 +0,0 @@
-registerDCN=true

+ 0 - 1
search-console/src/main/resources/prod/sys.properties

@@ -1 +0,0 @@
-registerDCN=true

+ 6 - 12
search-console/src/main/resources/spring/applicationContext.xml

@@ -16,17 +16,11 @@
 	<!-- 注册spring上下文对象 -->
 	<bean class="com.uas.search.console.support.ApplicationContextRegister" />
 
-	<!-- 系统运行参数注入 -->
-	<util:properties id="sys"
-		location="classpath*:${profile}/sys.properties" />
-	<!-- 容器启动之后执行 -->
-	<bean class="com.uas.search.console.support.ContextRefreshedProcessor" />
-
 	<!-- 扫描注解 -->
 	<context:annotation-config />
 	<!-- 扫描的包 -->
 	<context:component-scan base-package="com.uas.search.console" />
-
+	
 	<!-- dataSource -->
 	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
 		destroy-method="close">
@@ -123,11 +117,11 @@
 		<property name="configLocation" value="classpath:spring/ehcache.xml"></property>
 		<property name="shared" value="true"></property>
 	</bean>
-
+	
 	<!-- jpa -->
-	<import resource="jpa.xml" />
-
+	<import resource="jpa.xml"/>
+	
 	<!-- dubbo 服务 -->
-	<import resource="provider.xml" />
-
+	<import resource="provider.xml"/>
+	
 </beans>

+ 0 - 1
search-console/src/main/resources/test/sys.properties

@@ -1 +0,0 @@
-registerDCN=true