首页 文章 精选 留言 我的

精选列表

搜索[API],共10000篇文章
优秀的个人博客,低调大师

Android API 中文 (55) —— ListAdapter

正文 一、结构 public interfaceListAdapterextendsAdapter android.widget.ListAdapter 直接子类 ArrayAdapter<T>, BaseAdapter, CursorAdapter, HeaderViewListAdapter, ResourceCursorAdapter, SimpleAdapter, SimpleCursorAdapter, WrapperListAdapter 二、概述 扩展Adapter是在ListView与数据之间的一座桥梁。通常数据来自于游标,但不是必须的。ListView可以显示包含在ListAdapter里的所有数据。 三、公共方法 public abstract booleanareAllItemsEnabled() 在ListAdapter中所有的项目都是可用的?如果是,则代表所有的项目都是可选择,可用鼠标点击的。 返回值 如果所有项目是可用的返回真 public abstract booleanisEnabled(int position) 如果指定的位置不是一个隔离(separator)项目(隔离项目是一个不可选择,不可用鼠标点击的项目)则返回真。如果位置是无效的,其结果将是不确定的。在这种情况下一个ArrayIndexOutOfBoundsException(越界)异常将抛出。 参数 position项目的索引 返回值 如果这个项目不是一个隔离(separator)项目则返回真。 本文转自over140 51CTO博客,原文链接:http://blog.51cto.com/over140/582570,如需转载请自行联系原作者

优秀的个人博客,低调大师

ElasticSearch1.7 java api

package cn.xdf.wlyy.solr.utils; import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.ResourceBundle;import java.util.concurrent.ExecutionException; import org.apache.commons.lang.StringUtils;import org.apache.log4j.Logger;import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;import org.elasticsearch.action.delete.DeleteResponse;import org.elasticsearch.action.index.IndexResponse;import org.elasticsearch.action.search.SearchRequestBuilder;import org.elasticsearch.action.search.SearchResponse;import org.elasticsearch.action.update.UpdateRequest;import org.elasticsearch.action.update.UpdateResponse;import org.elasticsearch.client.transport.TransportClient;import org.elasticsearch.common.settings.ImmutableSettings;import org.elasticsearch.common.settings.Settings;import org.elasticsearch.common.text.Text;import org.elasticsearch.common.transport.InetSocketTransportAddress;import org.elasticsearch.index.query.BoolQueryBuilder;import org.elasticsearch.index.query.QueryBuilder;import org.elasticsearch.index.query.QueryBuilders;import org.elasticsearch.search.SearchHit;import org.elasticsearch.search.SearchHits;import org.elasticsearch.search.highlight.HighlightField; import com.alibaba.fastjson.JSONObject; import cn.xdf.wlyy.bbyh.vo.SearchParVo;import cn.xdf.wlyy.utils.PagedResult; /** * Title. <br> * ElasticSearch工具类. * <p> * Copyright: Copyright (c) 2017年7月7日 下午1:09:36 * <p> * <p> * Author: jinxudong@xdf.cn * <p> * Version: 1.0 * <p> *//** * Title. <br> * ElasticSearch 工具类. * <p> * Copyright: Copyright (c) 2017年7月10日 上午9:05:30 * <p> * 2016-3-21 Company: 北京新东方学校 * <p> * Author: jinxudong@xdf.cn * <p> * Version: 1.0 * <p> */public class EsUtil { /** 启用日志 */ private static Logger logger = Logger.getLogger(EsUtil.class); private static TransportClient client; private static ResourceBundle resource = ResourceBundle.getBundle("es"); /** 索引库名称 */ private static String index = resource.getString("es.db"); /** 索引表名称 */ private static String type = resource.getString("es.table"); /** 集群分片数 */ private static String shards_str = resource.getString("es.shards"); private static Integer shards = Integer.parseInt(shards_str); private static SearchRequestBuilder searchRequestBuilder; // 获取集群名称 private static String clustername = resource.getString("es.cluster.name"); // 获取集群ip/域名 private static String hostname = resource.getString("es.hostname"); // 获取第一个节点端口号 private static String port1 = resource.getString("es.port.one"); // 获取第一个节点端口号 private static String port2 = resource.getString("es.port.two"); private static Settings settings; //es加载一次 避免多次链接造成内存溢出 或者使用单例模式 static { settings = ImmutableSettings.settingsBuilder() // client.transport.sniff=true // 客户端嗅探整个集群的状态,把集群中其它机器的ip地址自动添加到客户端中,并且自动发现新加入集群的机器 .put("client.transport.sniff", true).put("client", true)// 仅作为客户端连接 .put("data", false).put("cluster.name", clustername)// 集群名称 .build(); client = new TransportClient(settings).addTransportAddress(new InetSocketTransportAddress(hostname, Integer.parseInt(port1)))// TCP // 连接地址 .addTransportAddress(new InetSocketTransportAddress(hostname, Integer.parseInt(port2))); } /** * 创建索引 写入elasticsearch * * @param jsonlist * 要创建索引的jsonlist数据 */ public static void createIndex(List<JSONObject> jsonlist) { try { // 创建索引 for (int i = 0; i < jsonlist.size(); i++) { IndexResponse indexResponse = client.prepareIndex(index, type, jsonlist.get(i).getString("id")).setSource(jsonlist.get(i).toString()) .execute().actionGet(); if (indexResponse.isCreated()) { logger.info("写入索引库成功..."); } else { logger.info("写入索引库失败..."); } } } catch (Exception e) { logger.error(e); } } /** * 根据索引id删除 * * @param uids * 索引id */ public static void deleteIndex(List<String> uids) { for (int i = 0; i < uids.size(); i++) { DeleteResponse dResponse = client.prepareDelete(index, type, uids.get(i)).execute().actionGet(); if (dResponse.isContextEmpty()) { logger.info(uids.get(i) + "删除成功..."); } else { logger.info(uids.get(i) + "删除失败..."); } } } /** * 根据索引名称删除 * * @param indexName * 索引库名称 */ public static void deleteIndexLib(String indexName) { DeleteIndexResponse dResponse = client.admin().indices().prepareDelete(indexName).execute().actionGet(); if (dResponse.isContextEmpty()) { logger.info(indexName + "删除成功。"); } else { logger.info(indexName + "删除失败"); } } /** * @param uid * 要更新的索引id * @param json * 要更新的json数据 */ public static void updateIndex(String uid, JSONObject json) { UpdateRequest updateRequest = new UpdateRequest(); updateRequest.index(index); updateRequest.type(type); updateRequest.id(uid); updateRequest.doc(json); try { UpdateResponse updateResponse = client.update(updateRequest).get(); if (!updateResponse.isCreated()) { logger.info(uid + "更新成功"); } else { logger.info(uid + "更新失败"); } } catch (InterruptedException e) { // TODO Auto-generated catch block logger.error(e); } catch (ExecutionException e) { // TODO Auto-generated catch block logger.error(e); } } /** * 多字段查询 * * @param pageSize * 页面大小 * @param keyword * 查询关键字 * @param columns * 不确定多个索引字段 * @return map集合 map.put("dispage", disPage); map.put("jsonlist", * resultlist); */ public static Map<String, Object> query(Integer pageSize, Integer currentNo, SearchParVo vo, String... columns) { searchRequestBuilder = client.prepareSearch(index); HashMap<String, Object> map = new HashMap<String, Object>(); // 搜索结果集 List<JSONObject> resultlist = new ArrayList<JSONObject>(); QueryBuilder qb = null; QueryBuilder qb_state = null; QueryBuilder qb_dept = null; QueryBuilder qb_item = null; QueryBuilder qb_subject = null; QueryBuilder qb_regtype = null; QueryBuilder qb_disway = null; BoolQueryBuilder querybuilder = QueryBuilders.boolQuery(); if (StringUtils.isNotBlank(vo.getTitle())) { qb = QueryBuilders.multiMatchQuery(vo.getTitle(), columns); querybuilder.must(qb); // 必要条件 查询需要显示的内容 qb_state = QueryBuilders.matchPhraseQuery("state", "1"); querybuilder.must(qb_state); if (StringUtils.isNotBlank(vo.getDid())) { qb_dept = QueryBuilders.matchPhraseQuery("d_id", vo.getDid()); querybuilder.must(qb_dept); } if (StringUtils.isNotBlank(vo.getIid())) { qb_item = QueryBuilders.matchPhraseQuery("i_id", vo.getIid()); querybuilder.must(qb_item); } if (StringUtils.isNotBlank(vo.getSid())) { qb_subject = QueryBuilders.matchPhraseQuery("s_id", vo.getSid()); querybuilder.must(qb_subject); } if (StringUtils.isNotBlank(vo.getRegtype())) { qb_regtype = QueryBuilders.matchPhraseQuery("registration_type", vo.getRegtype()); querybuilder.must(qb_regtype); } if (StringUtils.isNotBlank(vo.getDisway())) { qb_disway = QueryBuilders.matchPhraseQuery("discount_way", vo.getDisway()); querybuilder.must(qb_disway); } } else { qb = QueryBuilders.matchAllQuery(); querybuilder.must(qb); } searchRequestBuilder.setQuery(querybuilder); SearchResponse response = searchRequestBuilder.execute().actionGet(); SearchHits hits = response.getHits(); // 记录总数 long total = hits.totalHits(); // 计算总页数 int totalPages = totalPage(1, pageSize, (int) total); // 每次开始的位置 int start = (currentNo - 1) * pageSize; // 添加高亮字段 searchRequestBuilder.addHighlightedField("title"); searchRequestBuilder.setHighlighterPreTags("<span style=\"color:red\">"); searchRequestBuilder.setHighlighterPostTags("</span>"); response = searchRequestBuilder.setFrom(start).setSize(pageSize).execute().actionGet(); SearchHit[] searchHits = response.getHits().hits(); // 封装分页对象信息 PagedResult disPage = new PagedResult(); disPage.setTotal(total); disPage.setPages(totalPages); disPage.setPageNo(currentNo); disPage.setPageSize(pageSize); for (SearchHit searchHit : searchHits) { Map<String, Object> dd = searchHit.getSource(); JSONObject json = (JSONObject) JSONObject.toJSON(dd); // 从设定的高亮域中取得指定域 Map<String, HighlightField> result = searchHit.highlightFields(); HighlightField titleField = result.get("title"); if (titleField != null) { // 取得定义的高亮标签 Text[] titleTexts = titleField.fragments(); // 为title串值增加自定义的高亮标签 String title = ""; for (Text text : titleTexts) { title += text; } json.put("title", title); } resultlist.add(json); } map.put("dispage", disPage); map.put("jsonlist", resultlist); return map; } /** * @param currentNo * 当前页 * @param pageSize * 一页显示多少条记录 * @param totalNum * 总记录 * @return */ public static int totalPage(Integer currentNo, Integer pageSize, int totalNum) { int totalPages = 0; if (totalNum % pageSize == 0) { totalPages = totalNum / pageSize; } else { totalPages = totalNum / pageSize + 1; } return totalPages; }}

优秀的个人博客,低调大师

Flink DataSet API Programming Guide

Example Program 编程的风格和spark很类似, ExecutionEnvironment -- SparkContext DataSet – RDD Transformations 这里用Java的接口,所以传入function需要用FlatMapFunction类对象 public class WordCountExample { public static void main(String[] args) throws Exception { final ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); DataSet<String> text = env.fromElements( "Who's there?", "I think I hear them. Stand, ho! Who's there?"); DataSet<Tuple2<String, Integer>> wordCounts = text .flatMap(new LineSplitter()) .groupBy(0) .sum(1); wordCounts.print(); } public static class LineSplitter implements FlatMapFunction<String, Tuple2<String, Integer>> { @Override public void flatMap(String line, Collector<Tuple2<String, Integer>> out) { for (String word : line.split(" ")) { out.collect(new Tuple2<String, Integer>(word, 1)); } } } } Specifying Keys 如何定义key, 1. 用tuple的index,如下用tuple的第一个和第二个做联合key DataSet<Tuple3<Integer,String,Long>> input = // [...] DataSet<Tuple3<Integer,String,Long> grouped = input .groupBy(0,1) .reduce(/*do something*/); 2. 对于POJO对象,使用Field Expressions // some ordinary POJO (Plain old Java Object) public class WC { public String word; public int count; } DataSet<WC> words = // [...] DataSet<WC> wordCounts = words.groupBy("word").reduce(/*do something*/); 3. 使用Key Selector Functions // some ordinary POJO public class WC {public String word; public int count;} DataSet<WC> words = // [...] DataSet<WC> wordCounts = words .groupBy( new KeySelector<WC, String>() { public String getKey(WC wc) { return wc.word; } }) .reduce(/*do something*/); Passing Functions to Flink 1. 实现function interface class MyMapFunction implements MapFunction<String, Integer> { public Integer map(String value) { return Integer.parseInt(value); } }); data.map (new MyMapFunction()); 或使用匿名类, data.map(new MapFunction<String, Integer> () { public Integer map(String value) { return Integer.parseInt(value); } }); 2. 使用Rich functions Rich functions provide, in addition to the user-defined function (map, reduce, etc), four methods:open,close,getRuntimeContext,andsetRuntimeContext. These are useful for parameterizing the function (seePassing Parameters to Functions), creating and finalizing local state, accessing broadcast variables (seeBroadcast Variables, and for accessing runtime information such as accumulators and counters (seeAccumulators and Counters, and information on iterations (seeIterations). Rich functions的使用和普通的function是一样的,不同的就是,多4个接口函数,可以用于一些特殊的场景,比如给function传参,或访问broadcast变量,accumulators和counter,因为这些场景你需要先getRuntimeContext class MyMapFunction extends RichMapFunction<String, Integer> { public Integer map(String value) { return Integer.parseInt(value); } }); Execution Configuration ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); ExecutionConfig executionConfig = env.getConfig(); enableClosureCleaner()/disableClosureCleaner(). The closure cleaner is enabled by default. The closure cleaner removes unneeded references to the surrounding class of anonymous functions inside Flink programs. With the closure cleaner disabled, it might happen that an anonymous user function is referencing the surrounding class, which is usually not Serializable. This will lead to exceptions by the serializer. 对于Java,比如传入function也要生成function对象,这样里面的function是会reference这个对象的,其实这种情况,你需要的只是function逻辑,所以closureCleaner会去掉这个reference 这样的好处是,传输类对象时候,是要求对象可序列化的,如果每个去实现序列号接口很麻烦,不实现又会报错,所以这里干脆clean掉这个reference getParallelism()/setParallelism(int parallelism)Set the default parallelism for the job. 设置Job的全局的parallelism getExecutionRetryDelay()/setExecutionRetryDelay(long executionRetryDelay)Sets the delay in milliseconds that the system waits after a job has failed, before re-executing it. The delay starts after all tasks have been successfully been stopped on the TaskManagers, and once the delay is past, the tasks are re-started. This parameter is useful to delay re-execution in order to let certain time-out related failures surface fully (like broken connections that have not fully timed out), before attempting a re-execution and immediately failing again due to the same problem. This parameter only has an effect if the number of execution re-tries is one or more.getExecutionMode()/setExecutionMode(). The default execution mode is PIPELINED. Sets the execution mode to execute the program. The execution mode defines whether data exchanges are performed in a batch or on a pipelined manner. 和失败重试相关的配置 enableObjectReuse()/disableObjectReuse()By default, objects are not reused in Flink. Enabling theobject reuse modewill instruct the runtime to reuse user objects for better performance. Keep in mind that this can lead to bugs when the user-code function of an operation is not aware of this behavior. 这个由于Java什么都要生成对象,比如function,所以会生成大量重复对象,这个可以打开object重用,提高性能 enableSysoutLogging()/disableSysoutLogging()JobManager status updates are printed toSystem.outby default. This setting allows to disable this behavior. 打开和关闭系统日志 getGlobalJobParameters()/setGlobalJobParameters()This method allows users to set custom objects as a global configuration for the job. Since theExecutionConfigis accessible in all user defined functions, this is an easy method for making configuration globally available in a job. 可以设置Job全局参数 其他的参数都是序列化相关的,不列了 Data Sinks Data sinks consume DataSets and are used to store or return them. Data sink operations are described using anOutputFormat. 可以custom output format: 比如写数据库, DataSet<Tuple3<String, Integer, Double>> myResult = [...] // write Tuple DataSet to a relational database myResult.output( // build and configure OutputFormat JDBCOutputFormat.buildJDBCOutputFormat() .setDrivername("org.apache.derby.jdbc.EmbeddedDriver") .setDBUrl("jdbc:derby:memory:persons") .setQuery("insert into persons (name, age, height) values (?,?,?)") .finish() ); 还有个功能,可以做locally的排序, DataSet<Tuple3<Integer, String, Double>> tData = // [...] DataSet<Tuple2<BookPojo, Double>> pData = // [...] DataSet<String> sData = // [...] // sort output on String field in ascending order tData.print().sortLocalOutput(1, Order.ASCENDING); // sort output on Double field in descending and Integer field in ascending order tData.print().sortLocalOutput(2, Order.DESCENDING).sortLocalOutput(0, Order.ASCENDING); Debugging 本地执行,LocalEnvironement final ExecutionEnvironment env = ExecutionEnvironment.createLocalEnvironment(); DataSet<String> lines = env.readTextFile(pathToTextFile); // build your program env.execute(); 便于调式的datasouce, final ExecutionEnvironment env = ExecutionEnvironment.createLocalEnvironment(); // Create a DataSet from a list of elements DataSet<Integer> myInts = env.fromElements(1, 2, 3, 4, 5); // Create a DataSet from any Java collection List<Tuple2<String, Integer>> data = ... DataSet<Tuple2<String, Integer>> myTuples = env.fromCollection(data); // Create a DataSet from an Iterator Iterator<Long> longIt = ... DataSet<Long> myLongs = env.fromCollection(longIt, Long.class); 便于输出的datasink, DataSet<Tuple2<String, Integer>> myResult = ... List<Tuple2<String, Integer>> outData = new ArrayList<Tuple2<String, Integer>>(); myResult.output(new LocalCollectionOutputFormat(outData)); Iteration Operators Iterations implement loops in Flink programs. The iteration operators encapsulate a part of the program and execute it repeatedly, feeding back the result of one iteration (the partial solution) into the next iteration. There are two types of iterations in Flink:BulkIterationandDeltaIteration. 参考,https://ci.apache.org/projects/flink/flink-docs-release-0.10/apis/iterations.html BulkIteration就是正常的Iteration,每次都处理全量数据 DeltaIteration,就是每次都只处理部分数据并delta更新,效率更高 Semantic Annotations Semantic annotations can be used to give Flink hints about the behavior of a function. 目的是做性能优化,优化器在明确知道function读参数的使用情况,比如如果知道某些field只是做forward,就可以保留它的sorting or partitioning信息 有3种语义annotation, Forwarded Fields Annotation 表示,输入的某个field会原封不动的copy到输出的某个field 下面的例子,表示输入的第一个field会copy到输出的第3个field 可以看到,输出tuple的第三个field是val.f0 @ForwardedFields("f0->f2") public class MyMap implements MapFunction<Tuple2<Integer, Integer>, Tuple3<String, Integer, Integer>> { @Override public Tuple3<String, Integer, Integer> map(Tuple2<Integer, Integer> val) { return new Tuple3<String, Integer, Integer>("foo", val.f1 / 2, val.f0); } } Non-Forwarded Fields 和上面相反,除指定的fields,其他fields都是原位置copy 例子,除输入的第二个field,其他都是原位置copy @NonForwardedFields("f1") // second field is not forwarded public class MyMap implements MapFunction<Tuple2<Integer, Integer>, Tuple2<Integer, Integer>> { @Override public Tuple2<Integer, Integer> map(Tuple2<Integer, Integer> val) { return new Tuple2<Integer, Integer>(val.f0, val.f1 / 2); } } Read Fields 表明这个fields会在function被读到或用到, 表明,输入的第一个field和第4个field会被读到或用到 @ReadFields("f0; f3") // f0 and f3 are read and evaluated by the function. public class MyMap implements MapFunction<Tuple4<Integer, Integer, Integer, Integer>, Tuple2<Integer, Integer>> { @Override public Tuple2<Integer, Integer> map(Tuple4<Integer, Integer, Integer, Integer> val) { if(val.f0 == 42) { return new Tuple2<Integer, Integer>(val.f0, val.f1); } else { return new Tuple2<Integer, Integer>(val.f3+10, val.f1); } } } Broadcast Variables Broadcast variables allow you to make a data set available to all parallel instances of an operation, in addition to the regular input of the operation. This is useful for auxiliary data sets, or data-dependent parameterization. The data set will then be accessible at the operator as a Collection. Broadcast: broadcast sets are registered by name viawithBroadcastSet(DataSet, String), and Access: accessible viagetRuntimeContext().getBroadcastVariable(String)at the target operator. // 1. The DataSet to be broadcasted DataSet<Integer> toBroadcast = env.fromElements(1, 2, 3); DataSet<String> data = env.fromElements("a", "b"); data.map(new RichMapFunction<String, String>() { @Override public void open(Configuration parameters) throws Exception { // 3. Access the broadcasted DataSet as a Collection Collection<Integer> broadcastSet = getRuntimeContext().getBroadcastVariable("broadcastSetName"); } @Override public String map(String value) throws Exception { ... } }).withBroadcastSet(toBroadcast, "broadcastSetName"); // 2. Broadcast the DataSet 这个场景,就是有些不大的公共数据,是要被所有的实例访问到的,比如一些查询表 上面的例子,会将toBroadcast设置为广播变量broadcastSetName,这样在运行时,可以用getRuntimeContext().getBroadcastVariable获取该变量使用 Passing Parameters to Functions 应该是如果将参数传递给function类,这个完全由java冗余导致的 首先,当然可以用类构造函数来传参数, ataSet<Integer> toFilter = env.fromElements(1, 2, 3); toFilter.filter(new MyFilter(2)); private static class MyFilter implements FilterFunction<Integer> { private final int limit; public MyFilter(int limit) { this.limit = limit; } @Override public boolean filter(Integer value) throws Exception { return value > limit; } } 自定义MyFilter,构造函数可以传入limit 也可以使用withParameters(Configuration) DataSet<Integer> toFilter = env.fromElements(1, 2, 3); Configuration config = new Configuration(); config.setInteger("limit", 2); toFilter.filter(new RichFilterFunction<Integer>() { private int limit; @Override public void open(Configuration parameters) throws Exception { limit = parameters.getInteger("limit", 0); } @Override public boolean filter(Integer value) throws Exception { return value > limit; } }).withParameters(config); 可以用withParameters将定义好的config传入function 然后用RichFunction的Open接口,将参数解析出来使用 这样和上面的比有啥好处,我怎么觉得上面那个看着更方便些?可以用匿名类? 当然你也可以用全局参数,这个和广播变量有什么区别?相同点就是都是全局可见,全局参数只能用于参数形式,广播变量可以是任意dataset Setting a custom global configuration Configuration conf = new Configuration(); conf.setString("mykey","myvalue"); final ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); env.getConfig().setGlobalJobParameters(conf); Accessing values from the global configuration public static final class Tokenizer extends RichFlatMapFunction<String, Tuple2<String, Integer>> { private String mykey; @Override public void open(Configuration parameters) throws Exception { super.open(parameters); ExecutionConfig.GlobalJobParameters globalParams = getRuntimeContext().getExecutionConfig().getGlobalJobParameters(); Configuration globConf = (Configuration) globalParams; mykey = globConf.getString("mykey", null); } // ... more here ... Accumulators & Counters 用于分布式计数,job结束的时候,会全部汇总 Flink currently has the followingbuilt-in accumulators. Each of them implements theAccumulatorinterface. IntCounter,LongCounterandDoubleCounter: See below for an example using a counter. Histogram: A histogram implementation for a discrete number of bins. Internally it is just a map from Integer to Integer. You can use this to compute distributions of values, e.g. the distribution of words-per-line for a word count program. //定义和注册counter private IntCounter numLines = new IntCounter(); getRuntimeContext().addAccumulator("num-lines", this.numLines); //在任意地方进行计数 this.numLines.add(1); //最终取得结果 myJobExecutionResult.getAccumulatorResult("num-lines") Execution Plans 首先可以打印出执行plan,json格式, final ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); ... System.out.println(env.getExecutionPlan()); 打开这个网页, The HTML document containing the visualizer is located undertools/planVisualizer.html. 将Json贴入,就可以看到执行计划, Web Interface Flink offers a web interface for submitting and executing jobs. If you choose to use this interface to submit your packaged program, you have the option to also see the plan visualization. The script to start the webinterface is located underbin/start-webclient.sh. After starting the webclient (per default onport 8080), your program can be uploaded and will be added to the list of available programs on the left side of the interface. 也可以通过web interface来提交job和查看执行计划

优秀的个人博客,低调大师

[ElasticSearch]Java API之TermQuery

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SunnyYoona/article/details/52852483 1. 词条查询(Term Query) 词条查询是ElasticSearch的一个简单查询。它仅匹配在给定字段中含有该词条的文档,而且是确切的、未经分析的词条。term 查询 会查找我们设定的准确值。term 查询本身很简单,它接受一个字段名和我们希望查找的值。 下面代码查询将匹配 college 字段中含有"California"一词的文档。记住,词条查询是未经分析的,因此需要提供跟索引文档中的词条完全匹配的词条。请注意,我们使用小写开头的california来搜索,而不是California,因为California一词在建立索引时已经变成了california(默认分词器)。 // Query TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("country", "AWxhOn".toLowerCase()); // Search SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index); searchRequestBuilder.setTypes(type); searchRequestBuilder.setQuery(termQueryBuilder); // 执行 SearchResponse searchResponse = searchRequestBuilder.get(); 参考:https://www.elastic.co/guide/en/elasticsearch/reference/2.4/query-dsl-term-query.html 2. 多词条查询(Terms Query) 词条查询(Term Query)允许匹配单个未经分析的词条,多词条查询(Terms Query)可以用来匹配多个这样的词条。只要指定字段包含任一我们给定的词条,就可以查询到该文档。 下面代码得到所有在 country 字段中含有 “德国” 或 "比利时" 的文档。 // Query TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery("country", "比利时", "德国"); // Search SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index); searchRequestBuilder.setTypes(type); searchRequestBuilder.setQuery(termsQueryBuilder); // 执行 SearchResponse searchResponse = searchRequestBuilder.get(); 参考:https://www.elastic.co/guide/en/elasticsearch/reference/2.4/query-dsl-terms-query.html 3. 范围查询(Range Query) 范围查询使我们能够找到在某一字段值在某个范围里的文档,字段可以是数值型,也可以是基于字符串的。范围查询只能针对单个字段。 方法: (1) gte() :范围查询将匹配字段值大于或等于此参数值的文档。 (2) gt() :范围查询将匹配字段值大于此参数值的文档。 (3) lte() :范围查询将匹配字段值小于或等于此参数值的文档。 (4) lt() :范围查询将匹配字段值小于此参数值的文档。 (5) from() 开始值 to() 结束值 这两个函数与includeLower()和includeUpper()函数配套使用。 (6) includeLower(true) 表示 from() 查询将匹配字段值大于或等于此参数值的文档。 (7) includeLower(false) 表示 from() 查询将匹配字段值大于此参数值的文档。 (8) includeUpper(true) 表示 to() 查询将匹配字段值小于或等于此参数值的文档。 (9) includeUpper(false) 表示 to() 查询将匹配字段值小于此参数值的文档。 // Query RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("age"); rangeQueryBuilder.from(19); rangeQueryBuilder.to(21); rangeQueryBuilder.includeLower(true); rangeQueryBuilder.includeUpper(true); //RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("age").gte(19).lte(21); // Search SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index); searchRequestBuilder.setTypes(type); searchRequestBuilder.setQuery(rangeQueryBuilder); // 执行 SearchResponse searchResponse = searchRequestBuilder.execute().actionGet(); 上面代码中的查询语句与下面的是等价的: QueryBuilder queryBuilder = QueryBuilders.rangeQuery("age").gte(19).lte(21); 参考:https://www.elastic.co/guide/en/elasticsearch/reference/2.4/query-dsl-range-query.html 4. 存在查询(Exists Query) 如果指定字段上至少存在一个no-null的值就会返回该文档。 // Query ExistsQueryBuilder existsQueryBuilder = QueryBuilders.existsQuery("name"); // Search SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index); searchRequestBuilder.setTypes(type); searchRequestBuilder.setQuery(existsQueryBuilder); // 执行 SearchResponse searchResponse = searchRequestBuilder.get(); 举例说明,下面的几个文档都会得到上面代码的匹配: { "name": "yoona" } { "name": "" } { "name": "-" } { "name": ["yoona"] } { "name": ["yoona", null ] } 第一个是字符串,是一个非null的值。 第二个是空字符串,也是非null。 第三个使用标准分析器的情况下尽管不会返回词条,但是原始字段值是非null的(Even though the standard analyzer would emit zero tokens, the original field is non-null)。 第五个中至少有一个是非null值。 下面几个文档不会得到上面代码的匹配: { "name": null } { "name": [] } { "name": [null] } { "user": "bar" } 第一个是null值。 第二个没有值。 第三个只有null值,至少需要一个非null值。 第四个与指定字段不匹配。 参考:https://www.elastic.co/guide/en/elasticsearch/reference/2.4/query-dsl-exists-query.html 5. 前缀查询(Prefix Query) 前缀查询让我们匹配这样的文档:它们的特定字段已给定的前缀开始。下面代码中我们查询所有country字段以"葡萄"开始的文档。 // Query PrefixQueryBuilder prefixQueryBuilder = QueryBuilders.prefixQuery("country", "葡萄"); // Search SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index); searchRequestBuilder.setTypes(type); searchRequestBuilder.setQuery(prefixQueryBuilder); // 执行 SearchResponse searchResponse = searchRequestBuilder.get(); 备注: 进行下面前缀查询,没有查找到相应信息,但是数据源中是有的: QueryBuilder queryBuilder = QueryBuilders.prefixQuery("club", "皇家马德里"); 产生以上差别的主要原因是club字段(默认mapping配置)进行了分析器分析了,索引中的数据已经不在是"皇家马德里",而country字段没有进行分析(mapping配置not_analyzed)。 参考:https://www.elastic.co/guide/en/elasticsearch/reference/2.4/query-dsl-prefix-query.html 6. 通配符查询(Wildcard Query) 通配符查询允许我们获取指定字段满足通配符表达式的文档,和前缀查询一样,通配符查询指定字段是未分析的(not analyzed)。 可以使用星号代替0个或多个字符,使用问号代替一个字符。星号表示匹配的数量不受限制,而后者的匹配字符数则受到限制。这个技巧主要用于英文搜索中,如输入““computer*”,就可以找到“computer、computers、computerised、computerized”等单词,而输入“comp?ter”,则只能找到“computer、compater、competer”等单词。注意的是通配符查询不太注重性能,在可能时尽量避免,特别是要避免前缀通配符(以以通配符开始的词条)。 // Query WildcardQueryBuilder wildcardQueryBuilder = QueryBuilders.wildcardQuery("country", "西*牙"); // Search SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index); searchRequestBuilder.setTypes(type); searchRequestBuilder.setQuery(wildcardQueryBuilder); // 执行 SearchResponse searchResponse = searchRequestBuilder.get(); 参考:https://www.elastic.co/guide/en/elasticsearch/reference/2.4/query-dsl-wildcard-query.html 7. 正则表达式查询(Regexp Query) 正则表达式查询允许我们获取指定字段满足正则表达式的文档,和前缀查询一样,正则表达式查询指定字段是未分析的(not analyzed)。正则表达式查询的性能取决于所选的正则表达式。如果我们的正则表达式匹配许多词条,查询将很慢。一般规则是,正则表达式匹配的词条数越高,查询越慢。 // Query RegexpQueryBuilder regexpQueryBuilder = QueryBuilders.regexpQuery("country", "(西班|葡萄)牙"); // Search SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index); searchRequestBuilder.setTypes(type); searchRequestBuilder.setQuery(regexpQueryBuilder); // 执行 SearchResponse searchResponse = searchRequestBuilder.get(); 参考:https://www.elastic.co/guide/en/elasticsearch/reference/2.4/query-dsl-regexp-query.html 8. 模糊查询(Fuzzy Query) 如果指定的字段是string类型,模糊查询是基于编辑距离算法来匹配文档。编辑距离的计算基于我们提供的查询词条和被搜索文档。如果指定的字段是数值类型或者日期类型,模糊查询基于在字段值上进行加减操作来匹配文档(The fuzzy query uses similarity based on Levenshtein edit distance for string fields, and a +/-margin on numeric and date fields)。此查询很占用CPU资源,但当需要模糊匹配时它很有用,例如,当用户拼写错误时。另外我们可以在搜索词的尾部加上字符 “~” 来进行模糊查询。 8.1 string类型字段 模糊查询生成所有可能跟指定词条的匹配结果(在fuzziness指定的最大编辑距离范围之内)。然后检查生成的所有结果是否是在索引中。 下面代码中模糊查询country字段为”西班牙“的所有文档,同时指定最大编辑距离为1(fuzziness),最少公共前缀为0(prefixLength),即不需要公共前缀。 // Query FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders.fuzzyQuery("country", "洗班牙"); // 最大编辑距离 fuzzyQueryBuilder.fuzziness(Fuzziness.ONE); // 公共前缀 fuzzyQueryBuilder.prefixLength(0); // Search SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index); searchRequestBuilder.setTypes(type); searchRequestBuilder.setQuery(fuzzyQueryBuilder); // 执行 SearchResponse searchResponse = searchRequestBuilder.get(); 8.2 数字和日期类型字段 与范围查询(Range Query)的around比较类似。形成在指定值上上下波动fuzziness大小的一个范围: -fuzziness <= field value <= +fuzziness 下面代码在18岁上下波动2岁,形成[17-19]的一个范围查询: // Query FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders.fuzzyQuery("age", "18"); fuzzyQueryBuilder.fuzziness(Fuzziness.TWO); // Search SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index); searchRequestBuilder.setTypes(type); searchRequestBuilder.setQuery(fuzzyQueryBuilder); // 执行 SearchResponse searchResponse = searchRequestBuilder.get(); 参考:https://www.elastic.co/guide/en/elasticsearch/reference/2.4/query-dsl-fuzzy-query.html 备注: 本代码基于ElasticSearch 2.4.1

优秀的个人博客,低调大师

MapReduce、Hbase接口API实践

读取hdfs中文件并做处理,取出卡号,通过卡号连接hbase查询出对应客户号,写入redis,因为不用输出,所以不调用context.write方法,整个操作在一个map中便可完成 protected HTable connect //setup方法被MapReduce框架仅且执行一次,在执行Map任务前,进行相关变量或者资源的集中初始化工作。若是将资源初始化工作放在方法map()中,导致Mapper任务在解析每一行输入时都会进行资源初始化工作,导致重复,程序运行效率不高! protected void setup(Context context) throws IOExcption,InterruptedException{ super.setup(context) String jobName = context.getJobName(); //文件索引值 cartNoIndex = conf.get(jobName + "source.key","7"); //创建hbase连接,hbase-site.xml配置文件需要在jar包中 Configuration config = HBaseConfiguration.create(); connect = new HTable(config,"tableName") } protected void map(writable key,Text value,Context context){ if(value == null || value.toString().trim().isEmpty()){ //计数器,记录处理的条数 context.getCounter(....).increment(1); }else{ String[] values = Utils.split(value,separator,true); //业务逻辑处理 int i = Integer.parseInt(cartNoIndex); if(i<values.length){ cardNo = values[i]; }else{ logger.error("cardNo cannot find"); } //从hbase中查询出对应客户号 String rowkey = HTableManager.generatRowkey(cardNo); Get getResult = new Get(rowkey.getBytes()); Result rs = connect.get(getResult); String curNo = Bytes.toString(rs.getValue("f1".getBytes(),"column_name".getBtes());RedisClient.getRedisClient().zincrbyset("spending:rank",countNum,custNo);protected void cleanup(context context)throws IOException,InterruptedException{ super.cleanup(context); connect.close();} public static String[] split(String value,String separator,boolean trimSpace){ String[] rtn = split(value.separator); if(trimSpace && rtn != null){ for(int i=0;i<rtn.length;i++){ rtn[i] = rtn[i].trim(); } } return rtn; } public static String[] split(String value,String separator){ String[] rtn = null; if(value != null){ boolean endBlank = false; if(value.endsWith(separator)){ value +=" "; endBlank = true; } separator = escapeExprSpecialWord(deparator); if(endBlank){ rtn(rtn.length-1) = ""; } } return rtn; } public static String escapeExprSpecialWord(String keyWord){ if(keyword != null && !keyword.isEmpty()){ String[] fbsArr = {"\\","|","(",")"}; for(String key : fbsArr){ if(keyword.contains(key){ keyword = keyword.replace(key,"\\"+key); } } } return keyword; }

优秀的个人博客,低调大师

MapReduce API 基本概念

1.序列化 序列化是指将结构化对象转为字节流以便于通过网络进行传输或写入持久存储的过程。反序列化指的是将字节流转为结构化对象的过程。 在 Hadoop MapReduce 中, 序列化的主 要 作用有两个: 永久存储和进程间通信。为了能够读取或者存储 Java 对象, MapReduce 编程模型要求用户输入和输出数据中的 key 和 value 必须是可序列化的。 在 Hadoop MapReduce 中 , 使一个 Java 对象可序列化的方法是让其对应的类实现 Writable 接口 。 但对于 key 而言,由于它是数据排序的关键字, 因此还需要提供比较两个 key 对象的方法。 为此,key对应类需实现WritableComparable 接口 , 它的类如图: 在package org.apache.hadoop.io 中的WritableComparable.java文件中定义: public interface WritableComparable<T> extends Writable, Comparable<T> { } 再来看看Writable接口的定义: public interface Writable { /** * Serialize the fields of this object to <code>out</code>. * * @param out <code>DataOuput</code> to serialize this object into. * @throws IOException */ void write(DataOutput out) throws IOException; /** * Deserialize the fields of this object from <code>in</code>. * * <p>For efficiency, implementations should attempt to re-use storage in the * existing object where possible.</p> * * @param in <code>DataInput</code> to deseriablize this object from. * @throws IOException */ void readFields(DataInput in) throws IOException; } 可以很明显的看出,write(DataOutput out)方法的作用是将指定对象的域序列化为out相同的类型;readFields(DataInput in)方法的作用是将in对象中的域反序列化,考虑效率因素,实现接口的时候应该使用已经存在的对象存储。 DataInput接口定义源代码如下: public interface DataInput { void readFully(byte b[]) throws IOException; void readFully(byte b[], int off, int len) throws IOException; int skipBytes(int n) throws IOException; boolean readBoolean() throws IOException; byte readByte() throws IOException; int readUnsignedByte() throws IOException; short readShort() throws IOException; int readUnsignedShort() throws IOException; char readChar() throws IOException; int readInt() throws IOException; long readLong() throws IOException; float readFloat() throws IOException; double readDouble() throws IOException; String readLine() throws IOException; String readUTF() throws IOException; } 每个方法的含义差不多,具体可参见java jdk源码 DataOutput接口定义源代码如下: public interface DataOutput { void write(int b) throws IOException; void write(byte b[]) throws IOException; void write(byte b[], int off, int len) throws IOException; void writeBoolean(boolean v) throws IOException; void writeByte(int v) throws IOException; void writeShort(int v) throws IOException; void writeChar(int v) throws IOException; void writeInt(int v) throws IOException; void writeLong(long v) throws IOException; void writeFloat(float v) throws IOException; void writeDouble(double v) throws IOException; void writeBytes(String s) throws IOException; void writeChars(String s) throws IOException; void writeUTF(String s) throws IOException; } WritableComparable可以用来比较,通常通过Comparator . 在hadoop的Map-Reduce框架中任何被用作key的类型都要实现这个接口。 看一个例子: public class MyWritableComparable implements WritableComparable { // Some data private int counter; private long timestamp; public void write(DataOutput out) throws IOException { out.writeInt(counter); out.writeLong(timestamp); } public void readFields(DataInput in) throws IOException { counter = in.readInt(); timestamp = in.readLong(); } public int compareTo(MyWritableComparable w) { int thisValue = this.value; int thatValue = ((IntWritable)o).value; return (thisValue &lt; thatValue ? -1 : (thisValue==thatValue ? 0 : 1)); } } 2.Reporter 参数 Reporter 是 MapReduce 提供给应用程序的工具。 如图所示,应用程序可使用Reporter 中的方法报告完成进度(progress)、设定状态消息(setStatus 以及更新计数器( incrCounter)。 Reporter 是一个基础参数。 MapReduce 对外提供的大部分组件, 包括 InputFormat、Mapper 和 Reducer 等,均在其主要方法中添加了该参数。 3.回调机制 回调机制是一种常见的设计模式。它将工作流内的某个功能按照约定的接口暴露给外部使用者, 为外部使用者提供数据,或要求外部使用者提供数据。 Hadoop MapReduce 对外提供的 5 个组件( InputFormat、 Mapper、 Partitioner、 Reducer 和OutputFormat) 实际上全部属于回调接口 。 当用户按照约定实现这几个接口后, MapReduce运行时环境会自 动调用它们。如图所示,MapReduce 给用户暴露了接口 Mapper, 当用户按照自己的应用程序逻辑实现自己的 MyMapper 后,Hadoop MapReduce 运行时环境会将输入数据解析成 key/value 对, 并调用 map() 函数迭代处理。

优秀的个人博客,低调大师

Java 封装 HDFS API 操作

代码下载地址:点击下载 一:环境介绍 hadoop:2.6 Ubuntu:15.10 eclipse:3.8.1 二:操作包括 判断某个文件夹是否存在 isExist(folder); 创建文件夹 mkdir(folder); 删除文件夹 rmr(folder); 列出所有文件夹 ls(folder); 递归列出所有文件夹 lsr(folder); 上传文件 put(local, folder); 下载文件 get(folder,local1); 删除文件 rm(folder); 显示文件 cat(folder); 三:代码演示 package user_thing_tuijian; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IOUtils; public class hdfsGYT { private static final String HDFS = "hdfs://127.0.0.1:9000/"; public hdfsGYT(String hdfs, Configuration conf ){ this.hdfsPath = hdfs; this.conf = conf; } public hdfsGYT() { // TODO Auto-generated constructor stub } private String hdfsPath; private Configuration conf = new Configuration() ; public static void main(String[] args) throws IOException, URISyntaxException{ hdfsGYT hdfsgyt = new hdfsGYT(); String folder = HDFS + "mr/groom_system/small2.csv"; String local = "/home/thinkgamer/Java/hadoop_shizhan/src/user_thing_tuijian/small2.csv"; String local1 = "/home/thinkgamer/Java/hadoop_shizhan/src/user_thing_tuijian"; //判断某个文件夹是否存在 //hdfsgyt.isExist(folder); //创建文件夹 //hdfsgyt.mkdir(folder); //删除文件夹 //hdfsgyt.rmr(folder); //列出所有文件夹 //hdfsgyt.ls(folder); //递归列出所有文件夹 //hdfsgyt.lsr(folder); //上传文件 //hdfsgyt.put(local, folder); //下载文件 //hdfsgyt.get(folder,local1); //删除文件 //hdfsgyt.rm(folder); //显示文件 //hdfsgyt.cat(folder); } //显示文件 private void cat(String folder) throws IOException, URISyntaxException { // 与hdfs建立联系 FileSystem fs = FileSystem.get(new URI(HDFS),new Configuration()); Path path = new Path(folder); FSDataInputStream fsdis = null; System.out.println("cat: " + folder); try { fsdis =fs.open(path); IOUtils.copyBytes(fsdis, System.out, 4096, false); } finally { IOUtils.closeStream(fsdis); fs.close(); } } //删除文件 private void rm(String folder) throws IOException, URISyntaxException { //与hdfs建立联系 FileSystem fs = FileSystem.get(new URI(HDFS),new Configuration()); Path path = new Path(folder); if(fs.deleteOnExit(path)){ fs.delete(path); System.out.println("delete:" + folder); }else{ System.out.println("The fiel is not exist!"); } fs.close(); } //下载文件 private void get(String remote, String local) throws IllegalArgumentException, IOException, URISyntaxException { // 建立联系 FileSystem fs = FileSystem.get(new URI(HDFS), new Configuration()); fs.copyToLocalFile(new Path(remote), new Path(local)); System.out.println("Get From : " + remote + " To :" + local); fs.close(); } //上传文件 private void put(String local, String remote) throws IOException, URISyntaxException { // 建立联系 FileSystem fs = FileSystem.get(new URI(HDFS), new Configuration()); fs.copyFromLocalFile(new Path(local), new Path(remote)); System.out.println("Put :" + local + " To : " + remote); fs.close(); } //递归列出所有文件夹 private void lsr(String folder) throws IOException, URISyntaxException { //与hdfs建立联系 FileSystem fs = FileSystem.get(new URI(HDFS),new Configuration()); Path path = new Path(folder); //得到该目录下的所有文件 FileStatus[] fileList = fs.listStatus(path); for (FileStatus f : fileList) { System.out.printf("name: %s | folder: %s | size: %d\n", f.getPath(), f.isDir() , f.getLen()); try{ FileStatus[] fileListR = fs.listStatus(f.getPath()); for(FileStatus fr:fileListR){ System.out.printf("name: %s | folder: %s | size: %d\n", fr.getPath(), fr.isDir() , fr.getLen()); } }finally{ continue; } } fs.close(); } //列出所有文件夹 private void ls(String folder) throws IOException, URISyntaxException { //与hdfs建立联系 FileSystem fs = FileSystem.get(new URI(HDFS),new Configuration()); Path path = new Path(folder); //得到该目录下的所有文件 FileStatus[] fileList = fs.listStatus(path); for (FileStatus f : fileList) { System.out.printf("name: %s | folder: %s | size: %d\n", f.getPath(), f.isDir() , f.getLen()); } fs.close(); } //删除文件夹 private void rmr(String folder) throws IOException, URISyntaxException { //与hdfs建立联系 FileSystem fs = FileSystem.get(new URI(HDFS),new Configuration()); Path path = new Path(folder); fs.delete(path); System.out.println("delete:" + folder); fs.close(); } //创建文件夹 public void mkdir(String folder) throws IOException, URISyntaxException { //与hdfs建立联系 FileSystem fs = FileSystem.get(new URI(HDFS),new Configuration()); Path path = new Path(folder); if (!fs.exists(path)) { fs.mkdirs(path); System.out.println("Create: " + folder); }else{ System.out.println("it is have exist:" + folder); } fs.close(); } //判断某个文件夹是否存在 private void isExist(String folder) throws IOException, URISyntaxException { //与hdfs建立联系 FileSystem fs = FileSystem.get(new URI(HDFS),new Configuration()); Path path = new Path(folder); if(fs.exists(path)){ System.out.println("it is have exist:" + folder); }else{ System.out.println("it is not exist:" + folder); } fs.close(); } }

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册