文档章节

搜索引擎(Solr-索引详解2)

这很耳东先生
 这很耳东先生
发布于 02/22 20:43
字数 4159
阅读 16
收藏 0

学习目标

1.掌握SolrJ的使用。
2.掌握索引API
3.掌握结构化数据导入DIH

 

SolrJ介绍

SolrJ是什么?

Solr提供的用于JAVA应用中访问solr服务API的客户端jar。在我们的应用中引入solrj:

<dependency>
  <groupId>org.apache.solr</groupId>
  <artifactId>solr-solrj</artifactId>
  <version>7.3.0</version>
</dependency>

SolrJ的核心API

SolrClient、SolrRequest、SolrResponse

SolrClient 的子类

HttpSolrClient – 与指定的一个solr节点通信的客户端
LBHttpSolrClient –负载均衡地访问一组节点的客户端
CloudSolrClient – 访问solrCloud的客户端
ConcurrentUpdateSolrClient –并发更新索引用的客户端

创建客户端时通用的配置选项

Base URL 
Timeouts

创建客户端时通用的配置选项

Base URL    基础URL

http://hostname:8983/solr/core1
http://hostname:8983/solr

Timeouts

final String solrUrl = "http://localhost:8983/solr";
return new HttpSolrClient.Builder(solrUrl)
    .withConnectionTimeout(10000)
    .withSocketTimeout(60000)
    .build();

用SolrJ索引文档

final SolrClient client = getSolrClient();

final SolrInputDocument doc = new SolrInputDocument();
doc.addField("id", UUID.randomUUID().toString());
doc.addField("name", "Amazon Kindle Paperwhite");

final UpdateResponse updateResponse = client.add("techproducts", doc);
// Indexed documents must be committed
client.commit("techproducts");

用SolrJ查询

final SolrClient client = getSolrClient();

final Map<String, String> queryParamMap = new HashMap<String, String>();
queryParamMap.put("q", "*:*");
queryParamMap.put("fl", "id, name");
queryParamMap.put("sort", "id asc");
MapSolrParams queryParams = new MapSolrParams(queryParamMap);

final QueryResponse response = client.query("techproducts", queryParams);
final SolrDocumentList documents = response.getResults();

print("Found " + documents.getNumFound() + " documents");
for(SolrDocument document : documents) {
  final String id = (String) document.getFirstValue("id");
  final String name = (String) document.getFirstValue("name");

  print("id: " + id + "; name: " + name);
}

Java 对象绑定

public static class TechProduct {
  @Field public String id;
  @Field public String name;

  public TechProduct(String id, String name) {
    this.id = id;  this.name = name;
  }

  public TechProduct() {}
}

索引

final SolrClient client = getSolrClient();

final TechProduct kindle = new TechProduct("kindle-id-4", "Amazon Kindle Paperwhite");
final UpdateResponse response = client.addBean("techproducts", kindle);

client.commit("techproducts");

查询

final SolrClient client = getSolrClient();

final SolrQuery query = new SolrQuery("*:*");
query.addField("id");
query.addField("name");
query.setSort("id", ORDER.asc);

final QueryResponse response = client.query("techproducts", query);
final List<TechProduct> products = response.getBeans(TechProduct.class);

SolrClient的API

SolrRequest 的API

method   path   queryParams  响应解析器 是否使用V2版API 认证信息

SolrRequest 的子类

SolrResponse 的API

SolrResponse 的子类

public class SolrJClientDemo {

	// baseSolrUrl 示例
	private static String baseSolrUrl = "http://localhost:8983/solr/";
	private static String baseSolrUrlWithCollection = "http://localhost:8983/solr/techproducts";

	/**
	 * HttpSolrClient:与一个solr Server 通过http进行通信
	 */
	public static SolrClient getHttpSolrClient(String baseSolrUrl) {
		return new HttpSolrClient.Builder(baseSolrUrl)
				.withConnectionTimeout(1000).withSocketTimeout(6000).build();
	}

	public static SolrClient getHttpSolrClient() {
		return new HttpSolrClient.Builder(baseSolrUrl)
				.withConnectionTimeout(1000).withSocketTimeout(6000).build();
	}

	/**
	 * LBHttpSolrClient: 负载均衡的httpSolrClient <br>
	 * 负载均衡方式: 轮询给定的多个solr server url。
	 * 当某个url不通时,url地址会从活跃列表移到死亡列表中,用下一个地址再次发送请求。<br>
	 * 对于死亡列表中的url地址,会定期(默认每隔1分钟,可设置)去检测是否变活了,再加入到活跃列表中。 <br>
	 * 注意: <br>
	 * 1、不可用于主从结构master/slave 的索引场景,因为主从结构必须通过主节点来更新。 <br>
	 * 2、对于SolrCloud(leader/replica),使用CloudSolrClient更好。
	 * 在solrCloud中可用它来进行索引更新,solrCloud中的节点会将请求转发到对应的leader。
	 */
	public static SolrClient getLBHttpSolrClient(String... solrUrls) {
		return new LBHttpSolrClient.Builder().withBaseSolrUrls(solrUrls)
				.build();
	}

	private static String baseSolrUrl2 = "http://localhost:7001/solr/";

	public static SolrClient getLBHttpSolrClient() {
		return new LBHttpSolrClient.Builder()
				.withBaseSolrUrls(baseSolrUrl, baseSolrUrl2).build();
	}

	/**
	 * 访问SolrCloud集群用CloudSolrClient<br>
	 * CloudSolrClient 实例通过访问zookeeper得到集群中集合的节点列表,<br>
	 * 然后通过LBHttpSolrClient来负载均衡地发送请求。<br>
	 * 注意:这个类默认文档的唯一键字段为“id”,如果不是的,通过 setIdField(String)方法指定。
	 */
	public static SolrClient getCloudSolrClient(List<String> zkHosts,
			Optional<String> zkChroot) {
		return new CloudSolrClient.Builder(zkHosts, zkChroot).build();
	}

	private static String zkServerUrl = "localhost:9983";

	public static SolrClient getCloudSolrClient() {
		List<String> zkHosts = new ArrayList<String>();
		zkHosts.add(zkServerUrl);
		Optional<String> zkChroot = Optional.empty();
		return new CloudSolrClient.Builder(zkHosts, zkChroot).build();
	}

	public static void main(String[] args) throws Exception {

		// HttpSolrClient 示例:
		SolrClient client = SolrJClientDemo.getHttpSolrClient();

		SolrInputDocument doc = new SolrInputDocument();
		doc.addField("id", UUID.randomUUID().toString());
		doc.addField("name", "HttpSolrClient");

		UpdateResponse updateResponse = client.add("techproducts", doc);
		// 记得要提交
		client.commit("techproducts");

		System.out.println("------------ HttpSolrClient ------------");
		System.out.println("add doc:" + doc);
		System.out.println("response: " + updateResponse.getResponse());

		client.close();

		// LBHttpSolrClient 示例
		client = SolrJClientDemo.getLBHttpSolrClient();
		doc.clear();
		doc.addField("id", UUID.randomUUID().toString());
		doc.addField("name", "LBHttpSolrClient");

		updateResponse = client.add("techproducts", doc);
		// 记得要提交
		client.commit("techproducts");
		System.out.println("------------ LBHttpSolrClient ------------");
		System.out.println("add doc:" + doc);
		System.out.println("response: " + updateResponse.getResponse());

		client.close();

		// CloudSolrClient 示例
		client = SolrJClientDemo.getCloudSolrClient();
		doc.clear();
		doc.addField("id", UUID.randomUUID().toString());
		doc.addField("name", "CloudSolrClient");

		updateResponse = client.add("techproducts", doc);
		// 记得要提交
		client.commit("techproducts");
		System.out.println("------------ CloudSolrClient ------------");
		System.out.println("add doc:" + doc);
		System.out.println("response: " + updateResponse.getResponse());

		client.close();
	}

}

 

索引 API 详解

Solr提供的数据提交方式简介

Solr中数据提交进行索引都是通过http请求,针对不同的数据源solr提供了几种方式来方便提交数据。

1.基于Apache  Tika 的 solr cell(Solr Content Extraction Library ),来提取上传文件内容进行索引。
2.应用中通过Index handler(即 index API)来提交数据。
3.通过Data Import Handler 来提交结构化数据源的数据

Post工具:提交服务器上的xml、json、csv数据文件及pdf、excel等富文本文件。

Index handler 是什么?

Index handler 索引处理器,是一种Request handler 请求处理器。
solr对外提供http服务,每类服务在solr中都有对应的request handler来接收处理,solr中提供了默认的处理器实现,如有需要我们也可提供我们的扩展实现,并在conf/solrconfig.xml中进行配置。

在 conf/solrconfig.xml中,requestHandler的配置就像我们在web.xml中配置servlet-mapping(或spring mvc 中配置controller 的requestMap)一样:配置该集合/内核下某个请求地址的处理类。    

Solrconfig中通过updateHandler元素配置了一个统一的更新请求处理器支持XML、CSV、JSON和javabin更新请求(映射地址为/update),它根据请求提交内容流的内容类型Content-Type将其委托给适当的ContentStreamLoader来解析内容,再进行索引更新。

配置一个requestHandler示例

<requestHandler name=“/update" class="solr.UpdateRequestHandler" />

Xml 格式数据索引更新

请求头中设置 Content-type: application/xml or Content-type: text/xml

添加、替换文档

<add> 操作,支持两个可选属性: commitWithin:限定在多少毫秒内完成 overwrite:指定当唯一键已存在时是否覆盖,默认true。

<add>
  <doc>
    <field name="authors">Patrick Eagar</field>
    <field name="subject">Sports</field>
    <field name="dd">796.35</field>
    <field name="numpages">128</field>
    <field name="desc"></field>
    <field name="price">12.40</field>
    <field name="title">Summer of the all-rounder</field>
    <field name="isbn">0002166313</field>
    <field name="yearpub">1982</field>
    <field name="publisher">Collins</field>
  </doc>
  <doc>
  ...
  </doc>
</add>

删除文档

<delete>
  <id>0002166313</id>
  <id>0031745983</id>
  <query>subject:sport</query>
  <query>publisher:penguin</query>
</delete>

<delete> 操作,支持两种删除方式:
1、根据唯一键
2、根据查询

组合操作

<update>
  <add>
    <doc><!-- doc 1 content --></doc>
  </add>
  <add>
    <doc><!-- doc 2 content --></doc>
  </add>
  <delete>
    <id>0002166313</id>
  </delete>
</update>
<response>
  <lst name="responseHeader">
    <int name="status">0</int>
    <int name="QTime">127</int>
  </lst>
</response>

响应的结果: Status=0表示成功 Qtime是耗时

提交、优化、回滚操作

<commit waitSearcher="false"/>
<commit waitSearcher="false" expungeDeletes="true"/>
<optimize waitSearcher="false"/>
<rollback/>

commit、optimize 属性说明:
waitSearcher:默认true,阻塞等待打开一个新的IndexSearcher并注册为主查询searcher,来让提交的改变可见。
expungeDeletes: (commit only) 默认false,合并删除文档量占比超过10%的段,合并过程中删除这些已删除的文档。
maxSegments: (optimize only) 默认1,优化时,将段合并为最多多少个段

JSON 格式数据索引更新

请求头中设置 Content-Type: application/json or Content-Type: text/json

添加、替换一个文档

{
  "id": "1",
  "title": "Doc 1"
}

添加、替换多个文档

[
  {
    "id": "1",
    "title": "Doc 1"
  },
  {
    "id": "2",
    "title": "Doc 2"
  }
]

在json中指定操作

{
  "add": {
    "doc": {
      "id": "DOC1",
      "my_field": 2.3,
      "my_multivalued_field": [ "aaa", "bbb" ]   
    }
  },
  "add": {
    "commitWithin": 5000, 
    "overwrite": false,  
    "doc": {
      "f1": "v1", 
      "f1": "v2"
    }
  },
  "commit": {},
  "optimize": { "waitSearcher":false },
  "delete": { "id":"ID" },  
  "delete": { "query":"QUERY" } 
}

根据唯一键删除的简写方式:

{ "delete":"myid" }
{ "delete":["id1","id2"] }

针对 JSON 格式数据提供的两个专用path

不需要在请求头中设置 Content-Type: application/json or Content-Type:text/json

 

结构化数据导入DIH

Solr结构化数据导入简介

Solr支持从关系数据库、基于http的数据源(如RSS和ATOM提要)、电子邮件存储库和结构化XML 中索引内容。

从外而内,我们来分析该如何实现数据导入。

1、我们如何触发solr进行数据导入?

需要在solrconfig.xml配置一个requestHandler,通过发出http请求来触发,这个requestHander称为Data import Handler (DIH)

<requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">
  <lst name="defaults">
    <str name="config">/path/to/my/DIHconfigfile.xml</str>
  </lst>
</requestHandler>

1、DataImportHandler这个类所在jar并没有包含在类目录中,我们需要在solrconfig.xml中引入这个jar;

2、在solrconfig.xml中引入DataImportHandler的jar

在solrconfig.xml中找到<lib>的部分,加入下面的

<lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-dataimporthandler-.*\.jar" />

2、solr接到请求后,它如何知道该从何处取什么数据进行索引?

这就需要一个配置文件来定义这些了:

<requestHandler name="/dataimport" class="solr.DataImportHandler">
  <lst name="defaults">
    <str name="config">dih-data-config.xml</str>
  </lst>
</requestHandler>

配置文件可以是绝对路径、或相对集合conf/的相对路径。

思考:你觉得在DIH的配置文件中需要配置些什么?以从数据库导入为例

从哪取数据?
取什么数据?
如何取?
取出的数据是否需要经中间处理?
取出的数据如何与模式中的字段对应?

DIH核心概念

Datasource       数据源
Entity             实体:数据库中的表、视图
Processor             处理器:执行从实体中加载数据
Transformer     转换器:对处理器加载的数据进行转换处理
field     定义实体中的列与模式字段的对应。

字段对应规则说明:

1、自动进行名字相同配对;
2、对于名字不同的通过显式配置 field的column、name属性指定

来看一些配置示例

在solr安装目录中的example/example-DIH/solr/ 下可以看到好几个导入示例。
1、请查看各示例的solrconfig.xml中通过<lib>导入了哪些数据导入相关的jar。
2、请查看各示例的DIH配置文件的定义。
3、请重点看看从关系数据库导入的示例。

从关系数据库导入实践

数据库:mysql 表结构如下

create table t_product(
	prod_id	varchar(64) PRIMARY key,
	name 	varchar(200)	not null,
	simple_intro LONGTEXT,
	price bigint,
	uptime datetime,
	brand_id varchar(64),
	last_modify_time datetime
);

create table t_brand(
	id varchar(64) PRIMARY key,
	name varchar(200) not null,
	last_modify_time datetime
);

create table t_cat(
	id varchar(64) PRIMARY key,
	name varchar(200) not null,
	last_modify_time datetime
);

create table t_prod_cat(
	prod_id varchar(64),
	cat_id	varchar(64) ,
	last_modify_time datetime
);

从关系数据库导入实践-步骤

1.拷贝mysql的驱动jar包到solr中。问,可以放到哪些目录下?
2.在myproducts集合的solrconfig.xml中配置DIH及<lib>
3.在myproducts集合的conf/目录下创建dih配置文件dih-data-config.xml
4.配置数据源

 

dataSource 数据源说明

单数据源

<dataSource type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost/dbname" user="db_username" password="db_password"/>

多数据源

<dataSource type="JdbcDataSource" name="ds-1" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://db1-host/dbname" user="db_username" password="db_password"/>
<dataSource type="JdbcDataSource" name="ds-2" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://db2-host/dbname" user="db_username" password="db_password"/>

说明:

1.name、type 是通用属性,type默认是jdbcDataSource
2.其他属性是非固定的,不同type可有不同的属性,可随意扩展。

配置我们的数据源

<dataSource driver="com.mysql.jdbc.Driver" 
	url="jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&amp;characterEncoding=utf-8&amp;serverTimezone=GMT" 
		user="root" password="root" />

说明: serverTimezone=GMT是为解决引入最新版mysql驱动jar报时区错误而加入的连接请求参数。

 

从关系数据库导入实践-步骤 

5.配置document对应的实体(我们要导入的数据)

<document> 下可包含一个或多个 <entity>数据实体

entity 数据实体通用属性说明

name (required) : 标识实体的唯一名
processor : 当数据源是非RDBMS 时,必须指定处理器。(默认是SqlEntityProcessor)
transformer : 要应用在该实体上的转换器。
dataSource : 当配置了多个数据源时,指定使用的数据源的名字。
pk : 实体的主键列名。只有在增量导入时才需要指定主键列名。和模式中的唯一键是两个不同的东西。
rootEntity : 默认document元素的子entity是rootEntity,如果把rootEntity属性设为false值,则它的子会被作为rootEntity(依次类推)。rootEntity返回的每一行会创建一个document。
onError : (abort|skip|continue) . 当处理entity的行为document的过程中发生异常该如何处理:默认是 abort,放弃导入。skip:跳过这个文档,continue:继续索引该文档。
preImportDeleteQuery : 在全量导入前,如需要进行索引清理cleanup,可以通过此属性指定一个清理的索引删除查询,否则用的是‘*:*’(删除所有)。只有<document>的直接子Entity设置此属性有效。
postImportDeleteQuery : 指定全量导入后需要进行索引清理的delete查询。只有<document>的直接子Entity设置此属性有效.

SqlEntityProcessor 的 entity 属性说明

query (required) : 从数据库中加载实体数据用的SQL语句。
deltaQuery : 仅用于增量导入,指定增量数据pk的查询SQL。
parentDeltaQuery : 指定增量关联父实体的pk的查询SQL。
deletedPkQuery :仅用于增量导入,被删除实体的pk查询SQL。
deltaImportQuery : (仅用于增量导入) .指定增量导入实体数据的查询SQL。如果没有指定该查询语句,solr将使用query属性指定的语句,经修改后来查询加载增量数据(这很容易出错)。在该语句中往往需要引用deltaQuery查询结果的列值,通过 ${dih.delta.<column-name>} 来引用,如:select * from tbl where id=${dih.delta.id}

 

从关系数据库导入实践-步骤

6.配置查询数据的SQL

7.配置获取关联表数据

entity 关系表示

实体关系(一对一、一对多、多对一、多对多),用子实体来表示,在子实体的SQL查询语句中可用${parentEntity.columnName}来引用父实体数据的列值。
一个实体可包含多个子实体。

导入API请求参数command(操作)的选项值说明

full-import : 请求启动全量导入:

http://<host>:<port>/solr/dataimport?command=full-import 返回导入正在进行中的状态信息,导入会在一个新线程中开启(可能会需要一定时间完成导入)。导入完成后,导入的开始时间将存入到conf/dataimport.properties 文件中,用于后面的增量导入。增量导入完成后也会存入增量开始的时间到这个文件,用于下一次增量导入。全量导入期间并不会阻塞solr查询。

可附加的参数有:
entity : 指定导入<document> 下的哪些实体(必须是直接子). 如果没有给定该参数,则是其下所有子entity。
clean : (default 'true') 指定是否在导入前清理索引
commit : (default ‘true’) 指定导入后是否提交
optimize : (default ‘true’ up to Solr 3.6, ‘false’ afterwards). 是否进行优化。
debug : (default ‘false’). 是否以调试模式运行,开发下使用。
调试模式下不会提交,除非明确指定commit=true. 

delta-import : 请求启动增量导入http://<host>:<port>/solr/dataimport?command=delta-import . 支持的附加参数: clean, commit, optimize and debug 同 full-import。
status : 导入是异步进行的,通过下面的请求获得导入的进度、结果状态信息:http://<host>:<port>/solr/dataimport.
reload-config : 请求重新加载dih配置文件:http://<host>:<port>/solr/dataimport?command=reload-config .
abort : 请求中止当前的操作:http://<host>:<port>/solr/dataimport?command=abort .

8.配置增量导入的SQL

增量导入中的特殊变量${dataimporter.last_index_time} 说明

这个变量是上次导入的开始时间。默认存储在conf/请求处理器名.properties文件中。我们可以在<dataConfig>下配置一个propertyWriter元素来设置它。

<propertyWriter dateFormat="yyyy-MM-dd HH:mm:ss" type="SimplePropertiesWriter" directory="data" filename="my_dih.properties" locale="en_US" />

说明:type在非cloud模式下默认是SimplePropertiesWriter,在cloud模式下默认是ZKPropertiesWriter

DIH配置文件中使用请求参数

如果你的DIH配置文件中需要使用请求时传人的参数,可用${dataimporter.request.paramname}表示引用请求参数。

配置示例:

<dataSource driver="org.hsqldb.jdbcDriver" url="${dataimporter.request.jdbcurl}" user="${dataimporter.request.jdbcuser}" password="${dataimporter.request.jdbcpassword}" />

请求传参示例:

http://localhost:8983/solr/dih/dataimport?command=full-import&jdbcurl=jdbc:hsqldb:./example-DIH/hsqldb/ex&jdbcuser=sa&jdbcpassword=secret

小结

1.Solr支持从很多种数据源导入数据
2.实现了很多的处理器及转换器

实际工作过程中如碰到了别的数据源的导入,一定要想到solr中应该有对应的解决方案。参考地址:
http://lucene.apache.org/solr/guide/7_3/uploading-structured-data-store-data-with-the-data-import-handler.html
https://wiki.apache.org/solr/DataImportHandle
 

DIH操作参考配置

<dataConfig>
    <dataSource driver="org.mysql.jdbc.Driver" 
	url="jdbc:mysql://127.0.0.1:3306/example?useUnicode=true"
	 user="sa" password="123456"/>
    <document>
        <entity name="product" query="select * from t_product" pk="prod_id"
         <!-- deltaQuery :增量操作时进行的查询  -->
         deltaQuery ="select prod_id from t_product where last_modify_time > '${dataimporter.last_index_time}'" 
         <!-- deltaImportQuery:deltaQuery 之后进行的查询 prod_id 是entity的pk   -->
         deltaImportQuery ="select * from t_product where prod_id ='${dih.delta.prod_id}'"
        >
	    <field column="prod_id" name="prodId" />
	    <field column="simple_intro" name="simpleIntro" />            
		<!-- 对应品牌 -->
            <entity name="brand"  pk='id'
                 query="select name from t_brand where id='${product.brand_id}'"
                     <!-- deltaQuery :增量操作时进行的查询  -->
                 deltaQuery ="select id from t_brand  where last_modify_time > '${dataimporter.last_index_time}'" 
                     <!-- parentDeltaQuery: 子操作更新完 父级折行的操作  -->
                 parentDeltaQuery ="select prod_id from t_product where brand_id='#{brand.id}' " 
             >
                <field name="name" column="brand" />
            </entity>
            	<!-- 商品类别 -->
            <entity name="productCat"
                    query="select prod_id,cat_id from t_product_cat where prod_id='${product.prod_id}'">
                <entity name="cat"
                        query="select name from t_cat where id = '${productCat.cat_id}'">
                    <field column="name" name="cat" />
                </entity>
            </entity>
        </entity>
    </document>
</dataConfig>

 

© 著作权归作者所有

共有 人打赏支持
这很耳东先生
粉丝 3
博文 71
码字总数 224407
作品 0
广州
私信 提问
搜索引擎(Solr-部署详解)

Solr两种部署模式介绍 Solr的两种部署模式 Solr程序包安装好后,可以以两种模式来启动solr服务器: 1.Standalone Server 独立服务器模式 适用于数据规模不大的场景 2.SolrCloud 分布式集群模...

这很耳东先生
02/14
0
0
搜索引擎(Solr-模式详解)

Schema介绍 Schema 是什么? 问题1:在lucene中我们要对文档字段进行索引存储,需要如何做? 问题2:现在我们使用Solr搜索服务平台了,不需要编码了,还需要定义如何索引存储字段吗? 需要一...

这很耳东先生
02/15
0
0
Solr简单介绍

简介 Solr是一个高性能,采用Java5开发,Solr基于Lucene的全文搜索服务器。同时对其进行了扩展,提供了比Lucene更为丰富的查询语言,同时实现了可配置、可扩展并对查询性能进行了优化,并且提...

邵鸿鑫
2016/06/29
0
0
搜索引擎(Solr-索引详解)

时间字段类型特别说明 Solr中提供的时间字段类型( DatePointField, DateRangeField,废除的TrieDateField )是以时间毫秒数来存储时间的。 要求字段值以ISO-8601标准格式来表示时间:YYYY-MM...

这很耳东先生
02/19
0
0
开源搜索平台选型:ElasticSearch、Solr

由于系统积累的数据量越来越多(如访问日志、log4j打印的日志等)且散布在各应用的各服务器中,使得日志的查看、存储管理变得非常复杂,不得不去各机器上查找与存储管理。有没有一种平台可以...

yown
2017/05/29
0
0

没有更多内容

加载失败,请刷新页面

加载更多

webstorm 常用设置

###常用快捷键 ctrl+D//复制粘贴当前行ctrl+W//选中单词ctrl+←/→ //以单词作为边界跳光标位置ctrl+alt+L//格式化代码shift+tab/tab//减少/扩大缩进(可以在代码中减少行缩进)ct...

niuhongxia
20分钟前
5
0
Web前端自动化单元测试

Web前端自动化单元测试 单元测试的很多,比如辅助开发,预测开发,提高模块可靠性等。 还可以提高项目开发思路。 前提需求 本文基于nodejs环境,需要jasmine和 Karma。 nodejs:不多说,很突出...

DrChenXX
23分钟前
3
0
漫漫优化路,总会错几步(记一次接口优化)

最近做了一个搜索接口的优化,反复压测了四次,终于达到要求了,记录一下,晚上加个鸡腿🍗 业务逻辑 从OpenSearch中检索出数据,然后各种填充组装数据,最后返回 逻辑看似很简单,当初我也...

java菜分享
27分钟前
1
0
springboot 统一异常处理(包含统一数据校验)

1、统一异常处理的优势 在开发中,我们是否遇到过如下两种奇葩现象: (1)只要没有成功,不管什么原因,前端界面给出提示:服务端错误/异常。哪怕是数据校验不过,也这样提示(嗯,反正先把...

编程SHA
30分钟前
3
0
基于arcface 人脸识别demo使用教程

最近在研究虹软家的arcface 人脸识别 demo,现在就给大家分享一下官方的demo ** 工程如何使用? ** 1.下载代码: git clone https://github.com/asdfqwrasdf/ArcFaceDemo.git 或者直接下载压缩...

是哇兴哥棒棒哒
31分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部