solr spring 简单封装
版本Solr6
代码参考github地址:https://github.com/suyin58/spring_solr
实现功能
1.区分环境:不同的环境下,需要进行区分,例如开发环境、主干测试环境、线上测试环境能够进行隔离,不能相互影响(通过collection)
2.区分业务:不用业务场景的搜索需要进行区分,例如文章搜索、客服问题搜索需要进行隔离,不能相互影响(通过collection)
3.项目启动时候,能够自动创建相关配置,相关collection集群,避免多环境情况下需要进行重复配置
4.提供简单的增删改查功能:(此处solr的schema配置使用简单的ID+content_sa)
实现思路:
1.通过Spring的方式对Bean进行管理
<!-- 搜索引擎--> <bean id="searchEngine" class="com.wjs.common.search.impl.SearchEngineSolrImpl"> <!-- # zookeeper地址 公用 --> <property name="zkHost" value="${system.zookeeper.address}" /> <!-- # app应用环境 公用 --> <property name="appEnv" value="${system.appenv.name}" /> <!-- # solr 搜索区分业务 --> <property name="searchCore" value="${search.solr.core.name}" /> <!-- # solr 每次接口调用超时时间 --> <property name="timeOut" value="${search.solr.timeout}" /> <!-- # solr 配置,如果search.solr.core.name在集群中不存在,那么初始化solr的配置 #search.solr.configpath=solr_help_center_config/ 示例目录为:classpath:solr_help_center_config/ --> <property name="cfgPath" value="${search.solr.configpath}" /> <!-- # solr 如果search.solr.core.name在集群中不存在,那么初始化集群的分片数量,构造函数中使用,建议与solr集群数量同步 --> <property name="numShards" value="${search.solr.numshards}" /> </bean>
2.SearchEngineSolrImpl初始化的时候,需要执行如下操作
2.1.通过appEnv和searchCore构建所需的solr分区名称(collectionName)
2.2.查看配置的collection是否存在(通过CollectionAdminRequest.List查询)
2.3.如果不存在
2.3.1.上传solr配置(通过org.apache.solr.cloud.ZkCLI命令进行配置的上传)
2.3.2.创建collection(通过CollectionAdminRequest.Create进行collection的创建)
2.4. 连接collectionName
@PostConstruct public void init() { collectionName = appEnv + "_" + searchCore; // 查看collection是否存在,如果不存在需要构建collection createCollectionWhenNotExist(); cloudSolrClient = new CloudSolrClient(zkHost); cloudSolrClient.setDefaultCollection(collectionName); cloudSolrClient.setZkClientTimeout(timeOut); cloudSolrClient.setZkConnectTimeout(3000); try { cloudSolrClient.connect(); } catch (Exception e) { LOGGER.error("solr connect error:{}", e.getMessage(), e); } } private void createCollectionWhenNotExist() { /** * 查看配置的collection是否存在,如果不存在,1.上传solr配置.2.创建collection */ CloudSolrClient solrClient = new CloudSolrClient(zkHost); solrClient.connect(); // 通过查询Collection的分布式情况,判断是否存在collection CollectionAdminRequest.List collectionList = new CollectionAdminRequest.List(); ArrayList<String> collectionNames = new ArrayList<String>(); try { CollectionAdminResponse response = collectionList.process(solrClient); LinkedTreeMap<String, Object> responseMap = (LinkedTreeMap<String, Object>) gson.fromJson(response.toString(), Object.class); collectionNames = (ArrayList<String>) responseMap.get("collections"); } catch (SolrServerException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } if (collectionNames.contains(collectionName)) { return; } String configName = "solr_" + collectionName + "_config"; try { PathMatchingResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver(); Resource[] resources = patternResolver.getResources(cfgPath); File rourceFile = resources[0].getFile(); // 上传配置 String[] args = { "-cmd", "upconfig", "-zkhost", zkHost, "-confdir", rourceFile.getAbsolutePath(), "-confname", configName }; ZkCLI.main(args); // 创建collection CollectionAdminRequest.Create collectionCreate = new CollectionAdminRequest.Create(); collectionCreate.setCollectionName(collectionName); collectionCreate.setConfigName(configName); collectionCreate.setNumShards(numShards); collectionCreate.process(solrClient); } catch (Exception e) { LOGGER.error("init solr collection error,collectionName:{} , errmsg:{}", collectionName, e.getMessage(), e); } } @Override public <T> void addDoc(String id, T doc) { SolrInputDocument document = new SolrInputDocument(); document.addField("id", id); try { Field field = doc.getClass().getDeclaredField("id"); field.setAccessible(true); field.set(doc, ""); } catch (Exception e) { // ignore } document.addField("content_sa", gson.toJson(doc)); try { UpdateResponse res = cloudSolrClient.add(document); LOGGER.info("solr add object success:{}", res); cloudSolrClient.commit(); } catch (SolrServerException e) { LOGGER.error("solr add object error,collection:{} doc:{} , errmsg:{}", collectionName, doc, e.getMessage(), e); } catch (Exception e) { LOGGER.error("solr add object error,collection:{} doc:{} , errmsg:{}", collectionName, doc, e.getMessage(), e); } }
3. 封装常用的增删改查代码
3.1 新增文档:addDoc(String id,T doc);
3.2 分页查询文档:get(String keyworld, Class<T> claz, Integer start, Integer limit);
3.3 删除文档:removeDoc(String id);
3.4 更新文档:updateDoc(String id,T doc);
@Override public <T> List<T> get(String keyworld, Class<T> claz, Integer start, Integer limit) { List<T> results = new ArrayList<T>(); try { SolrQuery params = new SolrQuery(); // 设置高亮 // params.setHighlight(true).setHighlightSimplePre("<span class='red'>") // .setHighlightSimplePost("</span>"); // query.setParam("hl.fl", "Content");//设置高亮字段 // query.setParam("fl", "ID,Published"); // the common parameters for all search params.set("q", "content_sa:" + keyworld); params.set("fl", "id,content_sa"); // field list 返回字段 params.set("start", start == null ? "0" : String.valueOf(start)); // 分页 params.set("rows", limit == null ? "10" : String.valueOf(limit)); QueryResponse response = cloudSolrClient.query(params); // System.out.println(params); // 查询出来的结果都保存在SolrDocumentList中 SolrDocumentList res = response.getResults(); for (SolrDocument document : res) { // 打印高亮信息 LOGGER.debug("solr query result:" + document.get("id").toString() + document.get("content_sa").toString()); T t = gson.fromJson(document.get("content_sa").toString(), claz); try { String id = document.get("id").toString(); Field field = claz.getDeclaredField("id"); field.setAccessible(true); field.set(t, id); } catch (Exception e) { // ignore } results.add(t); } } catch (SolrServerException e) { LOGGER.error("solr query error, collection :{} , errmsg{}", collectionName, e.getMessage(), e); } catch (Exception e) { LOGGER.error("solr query error, collection :{} , errmsg{}", collectionName, e.getMessage(), e); } return results; } @Override public <T> void removeDoc(String id) { try { cloudSolrClient.deleteById(String.valueOf(id)); cloudSolrClient.commit(); } catch (SolrServerException e) { LOGGER.error("solr delete error:{}", e.getMessage(), e); } catch (Exception e) { LOGGER.error("solr delete error:{}", e.getMessage(), e); } } @Override public <T> void updateDoc(String id, T doc) { addDoc(id, doc); }
需要注意事项:
相关代码请到github上面进行下载:https://github.com/suyin58/spring_solr
需要上传的solr配置(schema配置),已经在test/resource/solr_help_config目录下进行了定义,如果需要对schema的实现进行调整,需要同步调整该目录下的schenma配置
测试使用的test/resource/solr_help_config/managed-schema使用了 IKAnlyzer分词,需要在solr集群中配置IK分词