• 关于

    指定KEY排序

    的搜索结果

回答

我能猜测到为什么会有这样的结果:如果没有索引,那么做COLLSCAN是按$natural顺序遍历的,所以出来的也是自然排序;如果有索引,则会逐个key做IXSCAN,然后逐个放进结果集里,也就是你要的顺序。从编程的角度讲,这是有意义的。但是没有任何保证将来的MongoDB版本也会一直保持这样的行为。事实上大部分数据库在不指定排序的时候都会以随机顺序,也就是引擎认为最高效的顺序返回结果。所以即使现在最高效的顺序正好是你想要的顺序,不代表将来一直会这样。不要依赖这个功能,否则将来在某个版本升级的时候会出现非常奇怪且难以定位的问题。个人建议:如果可能,按照输入的顺序指定排序来得到正确的结果顺序。如果输入的顺序无法指定,在程序中自行排序。
a123456678 2019-12-02 03:00:39 0 浏览量 回答数 0

回答

我能猜测到为什么会有这样的结果:1.如果没有索引,那么做COLLSCAN是按$natural顺序遍历的,所以出来的也是自然排序;2.如果有索引,则会逐个key做IXSCAN,然后逐个放进结果集里,也就是你要的顺序。从编程的角度讲,这是有意义的。但是没有任何保证将来的MongoDB版本也会一直保持这样的行为。事实上大部分数据库在不指定排序的时候都会以随机顺序,也就是引擎认为最高效的顺序返回结果。所以即使现在最高效的顺序正好是你想要的顺序,不代表将来一直会这样。不要依赖这个功能,否则将来在某个版本升级的时候会出现非常奇怪且难以定位的问题。个人建议:1.如果可能,按照输入的顺序指定排序来得到正确的结果顺序。2.如果输入的顺序无法指定,在程序中自行排序。
蛮大人123 2019-12-02 02:48:53 0 浏览量 回答数 0

回答

TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按key的升序排序,也可以指定排序的比较器。当用Iterator遍历TreeMap时,得到的记录是排过序的。
huc_逆天 2021-01-08 15:47:18 0 浏览量 回答数 0

问题

【精品问答】Python3 实例80问(附源码解析)

Python3 实例80问(附源码解析) 1.Python Hello World 实例 2.Python 数字求和 3.Python 平方根 4.Python 二次方程 5.Python 计算三角形的...
珍宝珠 2020-02-17 13:11:47 1931 浏览量 回答数 3

问题

PhpSDK的搜索如何操作?(17)

删除某个字段的所有distinct排序信息 请求参数 参数名称类型描述distinctKeystring指定的字段 函数定义 function removeDistinct($distinctKey) 使用示例 $s...
轩墨 2019-12-01 20:58:56 1167 浏览量 回答数 0

回答

通常,这是通过比较两个不兼容的排序规则字符串或尝试将不同排序规则的数据选择到组合列中引起的。 该子句COLLATE允许您指定查询中使用的排序规则。 例如,以下WHERE子句将始终给出您发布的错误: WHERE 'A' COLLATE latin1_general_ci = 'A' COLLATE latin1_general_cs 您的解决方案是为查询中的两列指定共享排序规则。这是使用COLLATE子句的示例: SELECT * FROM table ORDER BY key COLLATE latin1_general_ci; 另一种选择是使用BINARY运算符: BINARY str是CAST(str AS BINARY)的简写。 您的解决方案可能看起来像这样: SELECT * FROM table WHERE BINARY a = BINARY b; 要么, SELECT * FROM table ORDER BY BINARY a;
保持可爱mmm 2020-05-10 19:20:25 0 浏览量 回答数 0

回答

TreeMap实现了SotredMap接口,它是有序的集合。 TreeMap底层数据结构是一个红黑树,每个key-value都作为一个红黑树的节点。 如果在调用TreeMap的构造函数时没有指定比较器,则根据key执行自然排序。
huc_逆天 2021-01-08 15:43:30 0 浏览量 回答数 0

回答

您不应对操纵列表进行排序,您可以指定key=...参数以确定要排序的内容,例如: sorted_list = sorted(names, key=lambda n: n.split('.', 2)[1].casefold()) 这会产生: sorted(names, key=lambda n: n.split('.', 2) [1].casefold()) ['Mr.Albert', 'Mrs.obama', 'Mr.usman'] casefold()是用来做一个区分大小写的比较,你的问题样本输出显示。如果需要区分大小写的比较,可以将其删除。
游客gsy3rkgcdl27k 2019-12-02 02:11:05 0 浏览量 回答数 0

问题

如何操作GetRange

行为: 读取指定主键范围内的数据。 请求结构:message GetRangeRequest {    required string table_name = 1;    required Di...
云栖大讲堂 2019-12-01 20:59:46 1379 浏览量 回答数 0

回答

MongoDB支持多种类型的索引,包括单字段索引、复合索引、多key索引、文本索引等,每种类型的索引有不同的使用场合。 按照类型可分为: 单字段索引 db.person.createIndex( {age: 1} ) 对person集合建立对age的索引。 {age: 1} 代表升序索引,也可以通过{age: -1}来指定降序索引,对于单字段索引,升序/降序效果是一样的。 复合索引 db.person.createIndex( {age: 1, name: 1} ) 他是单字段索引的升级,可以对多个字段进行索引。按第一个字段排序,第一个字段相同的文档按第二个字段排序。 多key索引 {"name" : "jack", "age" : 19, habbit: ["football, runnning"]} db.person.createIndex( {habbit: 1} ) // 自动创建多key索引 db.person.find( {habbit: "football"} ) 当索引的字段为数组时,创建出的索引称为多key索引,多key索引会为数组的每个元素建立一条索引,比如person表加入一个habbit字段(数组)用于描述兴趣爱好,需要查询有相同兴趣爱好的人就可以利用habbit字段的多key索引。 其他索引
montos 2020-05-24 11:30:12 0 浏览量 回答数 0

回答

1.具体区别如下: 我们在开发的过程中使用HashMap比较多,在Map中在Map 中插入、删除和定位元素,HashMap 是最好的选择。 但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。 如果需要输出的顺序和输入的相同,那么用LinkedHashMap 可以实现,它还可以按读取顺序来排列. HashMap是一个最常用的Map,它根据键的hashCode值存储数据,根据键可以直 接获取它的值,具有很快的访问速度。HashMap最多只允许一条记录的键为null, 允许多条记录的值为null。HashMap不支持线程同步,即任一时刻可以有多个线程 同时写HashMap,可能会导致数据的不一致性。如果需要同步,可以用Collections的 synchronizedMap方法使HashMap具有同步的能力。 Hashtable与HashMap类似,不同的是:它不允许记录的键或者值为空;它支持线程的 同步,即任一时刻只有一个线程能写Hashtable,因此也导致了Hashtable在写入时会比较慢。 LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的 记录肯定是先插入的。 在遍历的时候会比HashMap慢TreeMap能够把它保存的记录根据键排序,默认是按升序排序, 也可以指定排序的比较器。当用Iterator遍历TreeMap时,得到的记录是排过序的。 2.LinkedHashMap简述: LinkedHashMap是HashMap的一个子类,它保留插入的顺序,如果需要输出的顺序和 输入时的相同,那么就选用LinkedHashMap。 LinkedHashMap是Map接口的哈希表和链接列表实现,具有可预知的迭代顺序。此实现 提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保 证该顺序恒久不变。 LinkedHashMap实现与HashMap的不同之处在于,后者维护着一个运行于所有条目的双 重链接列表。此链接列表定义了迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序。 注意:此实现不是同步的。如果多个线程同时访问链接的哈希映射,而其中至少一个线程从结 构上修改了该映射,则它必须保持外部同步。 根据链表中元素的顺序可以分为:按插入顺序的链表,和按访问顺序(调用get方法)的链表。 默认是按插入顺序排序,如果指定按访问顺序排序,那么调用get方法后,会将这次访问的元素 移至链表尾部,不断访问可以形成按访问顺序排序的链表。 可以重写removeEldestEntry方法返 回true值指定插入元素时移除最老的元素。 3.LinkedHashMap的实现: 对于LinkedHashMap而言,它继承与HashMap、底层使用哈希表与双向链表来保存所有元 素。其基本操作与父类HashMap相似,它通过重写父类相关的方法,来实现自己的链接列表特性。 下面我们来分析LinkedHashMap的源代码: 类结构:public class LinkedHashMap extends HashMap implements Map 1) 成员变量: LinkedHashMap采用的hash算法和HashMap相同,但是它重新定义了数组中保存的元素Entry, 该Entry除了保存当前对象的引用外,还保存了其上一个元素before和下一个元素after的引用,从而 在哈希表的基础上又构成了双向链接列表。看源代码: //true表示按照访问顺序迭代,false时表示按照插入顺序 private final boolean accessOrder; /** 双向链表的表头元素。 */ private transient Entry header; /** LinkedHashMap的Entry元素。 继承HashMap的Entry元素,又保存了其上一个元素before和下一个元素after的引用。 */ private static class Entry extends HashMap.Entry { Entry<K,V> before, after; …… } HashMap.Entry: static class Entry implements Map.Entry { final K key; V value; Entry<K,V> next; final int hash; Entry(int h, K k, V v, Entry<K,V> n) { value = v; next = n; key = k; hash = h; } } 2) 初始化: 通过源代码可以看出,在LinkedHashMap的构造方法中,实际调用了父类HashMap的 相关构造方法来构造一个底层存放的table数组。如: public LinkedHashMap(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); accessOrder = false; } HashMap中的相关构造方法: public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); // Find a power of 2 >= initialCapacity int capacity = 1; while (capacity < initialCapacity) capacity <<= 1; this.loadFactor = loadFactor; threshold = (int)(capacity * loadFactor); table = new Entry[capacity]; init(); } 我们已经知道LinkedHashMap的Entry元素继承HashMap的Entry,提供了双向链表 的功能。在上述HashMap的构造器中,最后会调用init()方法,进行相关的初始化,这个 方法在HashMap的实现中并无意义,只是提供给子类实现相关的初始化调用。 LinkedHashMap重写了init()方法,在调用父类的构造方法完成构造后,进一步实现 了对其元素Entry的初始化操作。 void init() { header = new Entry<K,V>(-1, null, null, null); header.before = header.after = header; } 3) 存储: LinkedHashMap并未重写父类HashMap的put方法,而是重写了父类HashMap的put方法 调用的子方法void recordAccess(HashMap m) ,void addEntry(int hash, K key, V value, int bucketIndex) 和void createEntry(int hash, K key, V value, int bucketIndex),提供了自己 特有的双向链接列表的实现。 HashMap.put: public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; } 重写方法: void recordAccess(HashMap m) { LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m; if (lm.accessOrder) { lm.modCount++; remove(); addBefore(lm.header); } } void addEntry(int hash, K key, V value, int bucketIndex) { // 调用create方法,将新元素以双向链表的的形式加入到映射中。 createEntry(hash, key, value, bucketIndex); // 删除最近最少使用元素的策略定义 Entry<K,V> eldest = header.after; if (removeEldestEntry(eldest)) { removeEntryForKey(eldest.key); } else { if (size >= threshold) resize(2 * table.length); } } void createEntry(int hash, K key, V value, int bucketIndex) { HashMap.Entry<K,V> old = table[bucketIndex]; Entry<K,V> e = new Entry<K,V>(hash, key, value, old); table[bucketIndex] = e; // 调用元素的addBrefore方法,将元素加入到哈希、双向链接列表。 e.addBefore(header); size++; } private void addBefore(Entry existingEntry) { after = existingEntry; before = existingEntry.before; before.after = this; after.before = this; } 4) 读取: LinkedHashMap重写了父类HashMap的get方法,实际在调用父类getEntry()方法取得 查找的元素后,再判断当排序模式accessOrder为true时,记录访问顺序,将最新访问的 元素添加到双向链表的表头,并从原来的位置删除。由于的链表的增加、删除操作是常 量级的,故并不会带来性能的损失。 HashMap.containsValue: public boolean containsValue(Object value) { if (value == null) return containsNullValue(); Entry[] tab = table; for (int i = 0; i < tab.length ; i++) for (Entry e = tab[i] ; e != null ; e = e.next) if (value.equals(e.value)) return true; return false; } /*查找Map中是否包含给定的value,还是考虑到,LinkedHashMap拥有的双链表, 在这里Override是为了提高迭代的效率。 */ public boolean containsValue(Object value) { // Overridden to take advantage of faster iterator if (value==null) { for (Entry e = header.after; e != header; e = e.after) if (e.value==null) return true; } else { for (Entry e = header.after; e != header; e = e.after) if (value.equals(e.value)) return true; } return false; } /*该transfer()是HashMap中的实现:遍历整个表的各个桶位,然后对桶进行遍历得到 每一个Entry,重新hash到newTable中, //放在这里是为了和下面LinkedHashMap重写该法的比较, void transfer(Entry[] newTable) { Entry[] src = table; int newCapacity = newTable.length; for (int j = 0; j < src.length; j++) { Entry<K,V> e = src[j]; if (e != null) { src[j] = null; do { Entry<K,V> next = e.next; int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } while (e != null); } } } */ /** *transfer()方法是其父类HashMap调用resize()的时候调用的方法,它的作用是表扩容后, 把旧表中的key重新hash到新的表中。 *这里从写了父类HashMap中的该方法,是因为考虑到,LinkedHashMap拥有的双链表, 在这里Override是为了提高迭代的效率。 */ void transfer(HashMap.Entry[] newTable) { int newCapacity = newTable.length; for (Entry e = header.after; e != header; e = e.after) { int index = indexFor(e.hash, newCapacity); e.next = newTable[index]; newTable[index] = e; } } public V get(Object key) { // 调用父类HashMap的getEntry()方法,取得要查找的元素。 Entry<K,V> e = (Entry<K,V>)getEntry(key); if (e == null) return null; // 记录访问顺序。 e.recordAccess(this); return e.value; } void recordAccess(HashMap m) { LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m; // 如果定义了LinkedHashMap的迭代顺序为访问顺序, // 则删除以前位置上的元素,并将最新访问的元素添加到链表表头。 if (lm.accessOrder) { lm.modCount++; remove(); addBefore(lm.header); } } /** * Removes this entry from the linked list. */ private void remove() { before.after = after; after.before = before; } /*clear链表,设置header为初始状态/ public void clear() { super.clear(); header.before = header.after = header; } 5) 排序模式: LinkedHashMap定义了排序模式accessOrder,该属性为boolean型变量,对于访问 顺序,为true;对于插入顺序,则为false。 private final boolean accessOrder; 一般情况下,不必指定排序模式,其迭代顺序即为默认为插入顺序。看LinkedHashMap 的构造方法,如: public LinkedHashMap(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); accessOrder = false; } 这些构造方法都会默认指定排序模式为插入顺序。如果你想构造一个LinkedHashMap, 并打算按从近期访问最少到近期访问最多的顺序(即访问顺序)来保存元素,那么请使用 下面的构造方法构造LinkedHashMap: public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) { super(initialCapacity, loadFactor); this.accessOrder = accessOrder; } 该哈希映射的迭代顺序就是最后访问其条目的顺序,这种映射很适合构建LRU缓存。 LinkedHashMap提供了removeEldestEntry(Map.Entry eldest)方法。该方法可以提供 在每次添加新条目时移除最旧条目的实现程序,默认返回false,这样,此映射的行为将类 似于正常映射,即永远不能移除最旧的元素。 当有新元素加入Map的时候会调用Entry的addEntry方法,会调用removeEldestEntry方法, 这里就是实现LRU元素过期机制的地方,默认的情况下removeEldestEntry方法只返回false 表示元素永远不过期。 /** * This override alters behavior of superclass put method. It causes newly * allocated entry to get inserted at the end of the linked list and * removes the eldest entry if appropriate. */ void addEntry(int hash, K key, V value, int bucketIndex) { createEntry(hash, key, value, bucketIndex); // Remove eldest entry if instructed, else grow capacity if appropriate Entry<K,V> eldest = header.after; if (removeEldestEntry(eldest)) { removeEntryForKey(eldest.key); } else { if (size >= threshold) resize(2 * table.length); } } /** * This override differs from addEntry in that it doesn't resize the * table or remove the eldest entry. */ void createEntry(int hash, K key, V value, int bucketIndex) { HashMap.Entry<K,V> old = table[bucketIndex]; Entry e = new Entry(hash, key, value, old); table[bucketIndex] = e; e.addBefore(header); size++; } protected boolean removeEldestEntry(Map.Entry eldest) { return false; } 此方法通常不以任何方式修改映射,相反允许映射在其返回值的指引下进行自我修改。 如果用此映射构建LRU缓存,则非常方便,它允许映射通过删除旧条目来减少内存损耗。 例如:重写此方法,维持此映射只保存100个条目的稳定状态,在每次添加新条目时 删除最旧的条目。 private static final int MAX_ENTRIES = 100; protected boolean removeEldestEntry(Map.Entry eldest) { return size() > MAX_ENTRIES; } 其实LinkedHashMap几乎和HashMap一样,不同的是它定义了一个Entry header, 这个header不是放在Table里,它是额外独立出来的。LinkedHashMap通过继承hashMap 中的Entry,并添加两个属性Entry before,after,和header结合起来组成一个双 向链表,来实现按插入顺序或访问顺序排序
wangccsy 2019-12-02 01:48:36 0 浏览量 回答数 0

回答

算法是比较复杂又基础的学科,每个学编程的人都会学习大量的算法。而根据统计,以下这18个问题是面试中最容易遇到的,本文给出了一些基本答案,供算法方向工程师或对此感兴趣的程序员参考。 1)请简单解释算法是什么? 算法是一个定义良好的计算过程,它将一些值作为输入并产生相应的输出值。简单来说,它是将输入转换为输出的一系列计算步骤。 2)解释什么是快速排序算法? 快速排序算法能够快速排序列表或查询。它基于分割交换排序的原则,这种类型的算法占用空间较小,它将待排序列表分为三个主要部分: ·小于Pivot的元素 ·枢轴元素Pivot(选定的比较值) ·大于Pivot的元素 3)解释算法的时间复杂度? 算法的时间复杂度表示程序运行完成所需的总时间,它通常用大O表示法来表示。 4)请问用于时间复杂度的符号类型是什么? 用于时间复杂度的符号类型包括: ·Big Oh:它表示小于或等于目标多项式 ·Big Omega:它表示大于或等于目标多项式 ·Big Theta:它表示与目标多项式相等 ·Little Oh:它表示小于目标多项式 ·Little Omega:它表示大于目标多项式 5)解释二分法检索如何工作? 在二分法检索中,我们先确定数组的中间位置,然后将要查找的值与数组中间位置的值进行比较,若小于数组中间值,则要查找的值应位于该中间值之前,依此类推,不断缩小查找范围,直至得到最终结果。 6)解释是否可以使用二分法检索链表? 由于随机访问在链表中是不可接受的,所以不可能到达O(1)时间的中间元素。因此,对于链表来说,二分法检索是不可以的(对顺序链表或排序后的链表是可以用的)。 7)解释什么是堆排序? 堆排序可以看成是选择排序的改进,它可以定义为基于比较的排序算法。它将其输入划分为未排序和排序的区域,通过不断消除最小元素并将其移动到排序区域来收缩未排序区域。 8)说明什么是Skip list? Skip list数据结构化的方法,它允许算法在符号表或字典中搜索、删除和插入元素。在Skip list中,每个元素由一个节点表示。搜索函数返回与key相关的值的内容。插入操作将指定的键与新值相关联,删除操作可删除指定的键。 9)解释插入排序算法的空间复杂度是多少? 插入排序是一种就地排序算法,这意味着它不需要额外的或仅需要少量的存储空间。对于插入排序,它只需要将单个列表元素存储在初始数据的外侧,从而使空间复杂度为O(1)。 10)解释什么是“哈希算法”,它们用于什么? “哈希算法”是一个哈希函数,它使用任意长度的字符串,并将其减少为唯一的固定长度字符串。它用于密码有效性、消息和数据完整性以及许多其他加密系统。 11)解释如何查找链表是否有循环? 要知道链表是否有循环,我们将采用两个指针的方法。如果保留两个指针,并且在处理两个节点之后增加一个指针,并且在处理每个节点之后,遇到指针指向同一个节点的情况,这只有在链表有循环时才会发生。 12)解释加密算法的工作原理? 加密是将明文转换为称为“密文”的密码格式的过程。要转换文本,算法使用一系列被称为“键”的位来进行计算。密钥越大,创建密文的潜在模式数越多。大多数加密算法使用长度约为64到128位的固定输入块,而有些则使用流方法。 13)列出一些常用的加密算法? 一些常用的加密算法是: ·3-way ·Blowfish ·CAST ·CMEA ·GOST ·DES 和Triple DES ·IDEA ·LOKI等等 14)解释一个算法的最佳情况和最坏情况之间有什么区别? ·最佳情况:算法的最佳情况解释为算法执行最佳的数据排列。例如,我们进行二分法检索,如果目标值位于正在搜索的数据中心,则这就是最佳情况,最佳情况时间复杂度为0。 ·最差情况:给定算法的最差输入参考。例如快速排序,如果选择关键值的子列表的最大或最小元素,则会导致最差情况出现,这将导致时间复杂度快速退化到O(n2)。 15)解释什么是基数排序算法? 基数排序又称“桶子法”,是通过比较数字将其分配到不同的“桶里”来排序元素的。它是线性排序算法之一。 16)解释什么是递归算法? 递归算法是一个解决复杂问题的方法,将问题分解成较小的子问题,直到分解的足够小,可以轻松解决问题为止。通常,它涉及一个调用自身的函数。 17)提到递归算法的三个定律是什么? 所有递归算法必须遵循三个规律: ·递归算法必须有一个基点 ·递归算法必须有一个趋向基点的状态变化过程 ·递归算法必须自我调用 18)解释什么是冒泡排序算法? 冒泡排序算法也称为下沉排序。在这种类型的排序中,要排序的列表的相邻元素之间互相比较。如果它们按顺序排列错误,将交换值并以正确的顺序排列,直到最终结果“浮”出水面。 满意记得采纳哈
玄学酱 2019-12-02 01:18:44 0 浏览量 回答数 0

问题

OpenSearch如何聚合distinct子句?

子句说明 聚合子句可以在一定程度上保证展示结果的多样性,以提升用户体验。如一次查询可以查出很多的文档,但是如果某个用户的多个文档分值都比较高,则都排在了前面,导致一页中所展示的结果...
轩墨 2019-12-01 20:57:16 1482 浏览量 回答数 0

问题

JavaSDK(标准/高级)V3的SearchParamsBuilder有什么用?(2)

禁用某个功能 接口定义 禁用某个功能SearchParamsBuilder        addDisableFunction(String function,String value) 参数描述 参数名称类型描述fu...
轩墨 2019-12-01 21:01:40 1122 浏览量 回答数 0

回答

作为缓存系统都要定期清理无效数据,就需要一个主键失效和淘汰策略.   在Redis当中,有生存期的key被称为volatile。在创建缓存时,要为给定的key设置生存期,当key过期的时候(生存期为0),它可能会被删除。   1、影响生存时间的一些操作   生存时间可以通过使用 DEL 命令来删除整个 key 来移除,或者被 SET 和 GETSET 命令覆盖原来的数据,也就是说,修改key对应的value和使用另外相同的key和value来覆盖以后,当前数据的生存时间不同。   比如说,对一个 key 执行INCR命令,对一个列表进行LPUSH命令,或者对一个哈希表执行HSET命令,这类操作都不会修改 key 本身的生存时间。另一方面,如果使用RENAME对一个 key 进行改名,那么改名后的 key的生存时间和改名前一样。   RENAME命令的另一种可能是,尝试将一个带生存时间的 key 改名成另一个带生存时间的 another_key ,这时旧的 another_key (以及它的生存时间)会被删除,然后旧的 key 会改名为 another_key ,因此,新的 another_key 的生存时间也和原本的 key 一样。使用PERSIST命令可以在不删除 key 的情况下,移除 key 的生存时间,让 key 重新成为一个persistent key 。   2、如何更新生存时间   可以对一个已经带有生存时间的 key 执行EXPIRE命令,新指定的生存时间会取代旧的生存时间。过期时间的精度已经被控制在1ms之内,主键失效的时间复杂度是O(1),   EXPIRE和TTL命令搭配使用,TTL可以查看key的当前生存时间。设置成功返回 1;当 key 不存在或者不能为 key 设置生存时间时,返回 0 。   最大缓存配置   在 redis 中,允许用户设置最大使用内存大小   server.maxmemory   默认为0,没有指定最大缓存,如果有新的数据添加,超过最大内存,则会使redis崩溃,所以一定要设置。redis 内存数据集大小上升到一定大小的时候,就会实行数据淘汰策略。   redis 提供 6种数据淘汰策略:   . volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰   . volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰   . volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰   . allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰   . allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰   . no-enviction(驱逐):禁止驱逐数据   注意这里的6种机制,volatile和allkeys规定了是对已设置过期时间的数据集淘汰数据还是从全部数据集淘汰数据,后面的lru、ttl以及random是三种不同的淘汰策略,再加上一种no-enviction永不回收的策略。   使用策略规则:   1、如果数据呈现幂律分布,也就是一部分数据访问频率高,一部分数据访问频率低,则使用allkeys-lru   2、如果数据呈现平等分布,也就是所有的数据访问频率都相同,则使用allkeys-random   三种数据淘汰策略:   ttl和random比较容易理解,实现也会比较简单。主要是Lru最近最少使用淘汰策略,设计上会对key 按失效时间排序,然后取最先失效的key进行淘汰
不语奈何 2020-01-09 19:51:00 0 浏览量 回答数 0

回答

1 and or 使用 >db.col.find({$or:[{key1: value1}, {key2:value2}]}) 12 where使用,和sql一样 查询已经有回款,但是没有完成回款的订单 >order >db.info.find({'$where': "this.price > this.received_money",status:2}).count() 123 条件操作符号 (>) 大于 - $gt(<) 小于 - $lt(>=) 大于等于 - $gte(<= ) 小于等于 - $ltedb.col.find({likes : {$lt : 150}}) 4 数组嵌套查询 rosterdb.domain_set.find({}) { "_id" : ObjectId("55cdb554b9518f0121a9870f"), "did" : NumberLong(75707), "hide_account" : 0, "pds" : { "details" : [ { "key" : "姓名", "type" : 0, "check" : 1 }, { "key" : "性别", "type" : 0, "check" : 1 }, { "key" : "联系方式", "type" : 0, "check" : 1 }, { "key" : "部门", "type" : 0, "check" : 1 }, { "key" : "职位", "type" : 0, "check" : 1 }, { "key" : "工号", "type" : 0 }, { "key" : "邮箱", "type" : 0 }, { "key" : "地址", "type" : 0 }, { "key" : "生日", "type" : 1 }, { "key" : "籍贯", "type" : 1 }, { "key" : "民族", "type" : 1 }, { "key" : "身份证号", "type" : 1, "check" : 1 }, { "key" : "婚姻状况", "type" : 1 }, { "key" : "子女", "type" : 1, "check" : 1 }, { "key" : "家庭住址", "type" : 1 }, { "key" : "紧急联系人", "type" : 1 }, { "key" : "紧急联系电话", "type" : 1 }, { "key" : "毕业日期", "type" : 1 }, { "key" : "入职日期", "type" : 1, "check" : 1 }, { "key" : "111", "type" : 3, "show_name" : "111", "check" : 1 }, { "key" : "222", "type" : 3, "show_name" : "222" }, { "key" : "333", "type" : 3, "show_name" : "333", "check" : 1 } ], "key_alloc" : 100 }, "udversion" : 50 } { "_id" : ObjectId("55d693c2b9518f0121ada57f"), "did" : NumberLong(11111), "hide_account" : 0, "udversion" : 1 } db.domain_set.find({"pds.details":{"$elemMatch":{"show_name" : "1111"}}}) db.test.find({"pds.details.19.key":"1111"}) 5 只显示某几个字段 查询did=10000的公司下面的订单,只显示price和order_id字段 order db.info.find({did:10000},{price:1,order_id:1}) 6 分页查询–limit和skip 查询did=10000的已经确认的订单,按照order_id(最新创建时间排序) order 显示前15个,第一页 db.info.find({did:10000,status:2},{order_id:1,price:1}).sort({order_id:-1}).limit(15) 加载16到30页,第二页 db.info.find({did:10000,status:2},{order_id:1,price:1}).sort({order_id:-1}).limit(15).skip(15) 7 aggregate使用,相当于shell里面的”|” 上面的几乎全部可以用aggregate进行查询 与sql对应关系 sql mongodb WHERE $match //match里面可以用and,or,以及逻辑判断,但是好像不能用whereGROUP BY $groupHAVING $matchSELECT $projectORDER BY $sortLIMIT $limitSUM() $sumCOUNT() $sum 特殊:暂时还没有用到$unwind 将数组元素拆分为独立字段$goNear 会返回一些坐标值,这些值以按照距离指定点距离由近到远进行排序 数字运算符$multiply 乘$add 加$subtract 减$mod 取模$divide 除 order项目中使用:1 统计某一段时间的订单总额和订单数量:db.info.aggregate([ { $match:{ did:10000, status:2, ordered_time:{$gt:1488297600000,$lt:1490976000000} } }, { $group: { _id: null, total: { $sum: "$price" }, order_num:{$sum:1} } } ])2 按照未回款的金额大小排序,同时显示订单金额,未回款金额db.info.aggregate([ { $match:{ did:10000, status:2, ordered_time:{$gt:1488297600000,$lt:1490976000000} } }, { $project:{ price:1, did:1, order_id:1, notpay:{$subtract:["$price","$received_money"]} } }, { $sort:{ notpay:-1 } } ]) 8 其他实例: 2 统计已经完成回款的订单 db.info.find({ $or:[{'$where': "this.price <= this.received_money"},{price:0}], did:10000, status:2, ordered_time:{$gt:1488297600000,$lt:1490976000000} }, {price:1}).sort({price:-1}) 3 查询所有未完成回款的订单1 db.info.find({ $or:[{'$where': "this.price > this.received_money"},{received_money:{$exists:false}}], did:10000, status:2, ordered_time:{$gt:1488297600000,$lt:1490976000000} }, {price:1}).sort({price:-1})
小六码奴 2019-12-02 02:02:28 0 浏览量 回答数 0

回答

首先遵循sql规范,然后可以提高你的并行度,最后,聚合的sql肯定会遇到shuffle,这就需要你解决好shuffle的问题,下面是我这你的一些技巧,希望对你有帮助 /** * @author BlueCat丶懒猫 * @title: SparkShuffleSolutions * @date 2019/11/18 12:37 * @desc: * 2.1 数据倾斜原理 *    在进行shuffle的时候,必须将各个节点上相同的key拉取到某个节点上的一个task来进行处理,此时如果某个key对应的数据量特别大的话,就会发生数据倾斜 * 2.2 数据倾斜问题发现与定位 *    通过Spark Web UI来查看当前运行的stage各个task分配的数据量,从而进一步确定是不是task分配的数据不均匀导致了数据倾斜。 * 知道数据倾斜发生在哪一个stage之后,接着我们就需要根据stage划分原理,推算出来发生倾斜的那个stage对应代码中的哪一部分, * 这部分代码中肯定会有一个shuffle类算子。通过countByKey查看各个key的分布。 * 2.3 数据倾斜解决方案 *     2.3.1 过滤少数导致倾斜的key *     2.3.2 提高shuffle操作的并行度 *     2.3.3 局部聚合和全局聚合 => solution1 * 2.3.4 将reduce join转为map join((小表几百M或者一两G))  => solution2 * 2.3.5 采样倾斜key并分拆join操作(join的两表都很大,但仅一个RDD的几个key的数据量过大) => solution3 * 2.3.6 使用随机前缀和扩容RDD进行join(RDD中有大量的key导致数据倾斜) => solution4 * 4 spark shuffle参数调优 * spark.shuffle.file.buffer * 默认值:32k * 参数说明:该参数用于设置shuffle write task的BufferedOutputStream的buffer缓冲大小。将数据写到磁盘文件之前,会先写入buffer缓冲中,待缓冲写满之后,才会溢写到磁盘。 * 调优建议:如果作业可用的内存资源较为充足的话,可以适当增加这个参数的大小(比如64k),从而减少shuffle write过程中溢写磁盘文件的次数,也就可以减少磁盘IO次数,进而提升性能。在实践中发现,合理调节该参数,性能会有1%~5%的提升。 * spark.reducer.maxSizeInFlight * 默认值:48m * 参数说明:该参数用于设置shuffle read task的buffer缓冲大小,而这个buffer缓冲决定了每次能够拉取多少数据。 * 调优建议:如果作业可用的内存资源较为充足的话,可以适当增加这个参数的大小(比如96m),从而减少拉取数据的次数,也就可以减少网络传输的次数,进而提升性能。在实践中发现,合理调节该参数,性能会有1%~5%的提升。 * spark.shuffle.io.maxRetries * 默认值:3 * 参数说明:shuffle read task从shuffle write task所在节点拉取属于自己的数据时,如果因为网络异常导致拉取失败,是会自动进行重试的。该参数就代表了可以重试的最大次数。如果在指定次数之内拉取还是没有成功,就可能会导致作业执行失败。 * 调优建议:对于那些包含了特别耗时的shuffle操作的作业,建议增加重试最大次数(比如60次),以避免由于JVM的full gc或者网络不稳定等因素导致的数据拉取失败。在实践中发现,对于针对超大数据量(数十亿~上百亿)的shuffle过程,调节该参数可以大幅度提升稳定性。 * spark.shuffle.io.retryWait * 默认值:5s * 参数说明:具体解释同上,该参数代表了每次重试拉取数据的等待间隔,默认是5s。 * 调优建议:建议加大间隔时长(比如60s),以增加shuffle操作的稳定性。 * spark.shuffle.memoryFraction * 默认值:0.2 * 参数说明:该参数代表了Executor内存中,分配给shuffle read task进行聚合操作的内存比例,默认是20%。 * 调优建议:在资源参数调优中讲解过这个参数。如果内存充足,而且很少使用持久化操作,建议调高这个比例,给shuffle read的聚合操作更多内存,以避免由于内存不足导致聚合过程中频繁读写磁盘。在实践中发现,合理调节该参数可以将性能提升10%左右。 * spark.shuffle.manager * 默认值:sort * 参数说明:该参数用于设置ShuffleManager的类型。Spark 1.5以后,有三个可选项:hash、sort和tungsten-sort。HashShuffleManager是Spark 1.2以前的默认选项,但是Spark 1.2以及之后的版本默认都是SortShuffleManager了。tungsten-sort与sort类似,但是使用了tungsten计划中的堆外内存管理机制,内存使用效率更高。 * 调优建议:由于SortShuffleManager默认会对数据进行排序,因此如果你的业务逻辑中需要该排序机制的话,则使用默认的SortShuffleManager就可以;而如果你的业务逻辑不需要对数据进行排序,那么建议参考后面的几个参数调优,通过bypass机制或优化的HashShuffleManager来避免排序操作,同时提供较好的磁盘读写性能。这里要注意的是,tungsten-sort要慎用,因为之前发现了一些相应的bug。 * spark.shuffle.sort.bypassMergeThreshold * 默认值:200 * 参数说明:当ShuffleManager为SortShuffleManager时,如果shuffle read task的数量小于这个阈值(默认是200),则shuffle write过程中不会进行排序操作,而是直接按照未经优化的HashShuffleManager的方式去写数据,但是最后会将每个task产生的所有临时磁盘文件都合并成一个文件,并会创建单独的索引文件。 * 调优建议:当你使用SortShuffleManager时,如果的确不需要排序操作,那么建议将这个参数调大一些,大于shuffle read task的数量。那么此时就会自动启用bypass机制,map-side就不会进行排序了,减少了排序的性能开销。但是这种方式下,依然会产生大量的磁盘文件,因此shuffle write性能有待提高。 * spark.shuffle.consolidateFiles * 默认值:false * 参数说明:如果使用HashShuffleManager,该参数有效。如果设置为true,那么就会开启consolidate机制,会大幅度合并shuffle write的输出文件,对于shuffle read task数量特别多的情况下,这种方法可以极大地减少磁盘IO开销,提升性能。 * 调优建议:如果的确不需要SortShuffleManager的排序机制,那么除了使用bypass机制,还可以尝试将spark.shffle.manager参数手动指定为hash,使用HashShuffleManager,同时开启consolidate机制。在实践中尝试过,发现其性能比开启了bypass机制的SortShuffleManager要高出10%~30%。 */
BlueCat丶懒猫 2020-01-09 19:27:54 0 浏览量 回答数 0

回答

同时在线超过服务器配置了,cpu和内存够的话就调调配置好了哦 ------------------------- 可以参考下这个  http://clin003.com/linux/debian-apache2-mysql-vps-2436/  优化mysql的MySQL配置优化mysql的主配置文件为/etc/mysql/my.cnf,优化之后,资源占用有明显的下降skip-innodb #不使用InnoDB数据库引擎,虽然InnoDB很强大,但对于小内存VPS就没啥必要使用了,关闭InnoDB引擎后,内存占用有明显的下降skip-external-locking #不使用外部锁,也就是操作系统提供的锁,这个选项现在默认是打开的key_buffer #与key_buffer_size是同一个参数,不过后者已经不推荐使用了,此参数指定索引缓冲区的大小,对于小内存VPS,16M的默认值有些大了,1M就差不多了query_cache_limit #不缓存大于此值的结果,设置为256Kquery_cache_size #用于缓存查询结果的内存大小,必须是1024的倍数,设置为query_cache_limit的16倍,即4Msort_buffer_size #排序缓存read_buffer_size #读缓存read_rnd_buffer_size #缓存通过关键字排序的行#这三个参数可以采用默认值,也可以参考/usr/share/doc/mysql-server-5.1/examples/my-small.cnf来设置
bcaiwa 2019-12-01 23:23:55 0 浏览量 回答数 0

回答

Spark 源码分析之ShuffleMapTask内存数据Spill和合并(文档详解):https://github.com/opensourceteams/spark-scala-maven/blob/master/md/ShuffleMapTaskSpillDiskFile.md Spark 源码分析之ShuffleMapTask内存数据Spill和合并更多资源分享SPARK 源码分析技术分享(视频汇总套装视频): https://www.bilibili.com/video/av37442139/github: https://github.com/opensourceteams/spark-scala-mavencsdn(汇总视频在线看): https://blog.csdn.net/thinktothings/article/details/84726769前置条件Hadoop版本: Hadoop 2.6.0-cdh5.15.0Spark版本: SPARK 1.6.0-cdh5.15.0JDK.1.8.0_191scala2.10.7技能标签Spark ShuffleMapTask 内存中的数据Spill到临时文件临时文件中的数据是如何定入的,如何按partition升序排序,再按Key升序排序写入(key,value)数据每个临时文件,都存入对应的每个分区有多少个(key,value)对,有多少次流提交数组,数组中保留每次流的大小如何把临时文件合成一个文件如何把内存中的数据和临时文件,进行分区,按key,排序后,再写入合并文件中内存中数据Spill到磁盘ShuffleMapTask进行当前分区的数据读取(此时读的是HDFS的当前分区,注意还有一个reduce分区,也就是ShuffleMapTask输出文件是已经按Reduce分区处理好的)SparkEnv指定默认的SortShuffleManager,getWriter()中匹配BaseShuffleHandle对象,返回SortShuffleWriter对象SortShuffleWriter,用的是ExternalSorter(外部排序对象进行排序处理),会把rdd.iterator(partition, context)的数据通过iterator插入到ExternalSorter中PartitionedAppendOnlyMap对象中做为内存中的map对象数据,每插入一条(key,value)的数据后,会对当前的内存中的集合进行判断,如果满足溢出文件的条件,就会把内存中的数据写入到SpillFile文件中满中溢出文件的条件是,每插入32条数据,并且,当前集合中的数据估值大于等于5m时,进行一次判断,会通过算法验证对内存的影响,确定是否可以溢出内存中的数据到文件,如果满足就把当前内存中的所有数据写到磁盘spillFile文件中SpillFile调用org.apache.spark.util.collection.ExternalSorter.SpillableIterator.spill()方法处理WritablePartitionedIterator迭代对象对内存中的数据进行迭代,DiskBlockObjectWriter对象写入磁盘,写入的数据格式为(key,value),不带partition的ExternalSorter.spillMemoryIteratorToDisk()这个方法将内存数据迭代对象WritablePartitionedIterator写入到一个临时文件,SpillFile临时文件用DiskBlockObjectWriter对象来写入数据临时文件的格式temp_local_+UUID遍历内存中的数据写入到临时文件,会记录每个临时文件中每个分区的(key,value)各有多少个,elementsPerPartition(partitionId) += 1 如果说数据很大的话,会每默认每10000条数据进行Flush()一次数据到文件中,会记录每一次Flush的数据大小batchSizes入到ArrayBuffer中保存并且在数据写入前,会进行排序,先按key的hash分区,先按partition的升序排序,再按key的升序排序,这样来写入文件中,以保证读取临时文件时可以分隔开每个临时文件的每个分区的数据,对于一个临时文件中一个分区的数据量比较大的话,会按流一批10000个(key,value)进行读取,读取的大小讯出在batchSizes数据中,就样读取的时候就非常方便了内存数据Spill和合并把数据insertAll()到ExternalSorter中,完成后,此时如果数据大的话,会进行溢出到临时文件的操作,数据写到临时文件后把当前内存中的数据和临时文件中的数据进行合并数据文件,合并后的文件只包含(key,value),并且是按partition升序排序,然后按key升序排序,输出文件名称:ShuffleDataBlockId(shuffleId, mapId, NOOP_REDUCE_ID) + UUID 即:"shuffle_" + shuffleId + "" + mapId + "" + reduceId + ".data" + UUID,reduceId为默认值0还会有一份索引文件: "shuffle_" + shuffleId + "" + mapId + "" + reduceId + ".index" + "." +UUID,索引文件依次存储每个partition的位置偏移量数据文件的写入分两种情况,一种是直接内存写入,没有溢出临时文件到磁盘中,这种是直接在内存中操作的(数据量相对小些),另外单独分析一种是有磁盘溢出文件的,这种情况是本文重点分析的情况ExternalSorter.partitionedIterator()方法可以处理所有磁盘中的临时文件和内存中的文件,返回一个可迭代的对象,里边放的元素为reduce用到的(partition,Iterator(key,value)),迭代器中的数据是按key升序排序的具体是通过ExternalSorter.mergeWithAggregation(),遍历每一个临时文件中当前partition的数据和内存中当前partition的数据,注意,临时文件数据读取时是按partition为0开始依次遍历的源码分析(内存中数据Spill到磁盘)ShuffleMapTask调用ShuffleMapTask.runTask()方法处理当前HDFS分区数据 调用SparkEnv.get.shuffleManager得到SortShuffleManager SortShuffleManager.getWriter()得到SortShuffleWriter 调用SortShuffleWriter.write()方法 SparkEnv.create() val shortShuffleMgrNames = Map( "hash" -> "org.apache.spark.shuffle.hash.HashShuffleManager", "sort" -> "org.apache.spark.shuffle.sort.SortShuffleManager", "tungsten-sort" -> "org.apache.spark.shuffle.sort.SortShuffleManager") val shuffleMgrName = conf.get("spark.shuffle.manager", "sort") val shuffleMgrClass = shortShuffleMgrNames.getOrElse(shuffleMgrName.toLowerCase, shuffleMgrName) val shuffleManager = instantiateClass[ShuffleManager](shuffleMgrClass) override def runTask(context: TaskContext): MapStatus = { // Deserialize the RDD using the broadcast variable. val deserializeStartTime = System.currentTimeMillis() val ser = SparkEnv.get.closureSerializer.newInstance() val (rdd, dep) = ser.deserialize[(RDD[_], ShuffleDependency[_, _, _])]( ByteBuffer.wrap(taskBinary.value), Thread.currentThread.getContextClassLoader) _executorDeserializeTime = System.currentTimeMillis() - deserializeStartTime metrics = Some(context.taskMetrics) var writer: ShuffleWriter[Any, Any] = null try { val manager = SparkEnv.get.shuffleManager writer = manager.getWriter[Any, Any](dep.shuffleHandle, partitionId, context) writer.write(rdd.iterator(partition, context).asInstanceOf[Iterator[_ <: Product2[Any, Any]]]) writer.stop(success = true).get } catch { case e: Exception => try { if (writer != null) { writer.stop(success = false) } } catch { case e: Exception => log.debug("Could not stop writer", e) } throw e } } SortShuffleWriter调用SortShuffleWriter.write()方法根据RDDDependency中mapSideCombine是否在map端合并,这个是由算子决定,reduceByKey中mapSideCombine为true,groupByKey中mapSideCombine为false,会new ExternalSorter()外部排序对象进行排序然后把records中的数据插入ExternalSorter对象sorter中,数据来源是HDFS当前的分区/* Write a bunch of records to this task's output / override def write(records: Iterator[Product2[K, V]]): Unit = { sorter = if (dep.mapSideCombine) { require(dep.aggregator.isDefined, "Map-side combine without Aggregator specified!") new ExternalSorter[K, V, C]( context, dep.aggregator, Some(dep.partitioner), dep.keyOrdering, dep.serializer) } else { // In this case we pass neither an aggregator nor an ordering to the sorter, because we don't // care whether the keys get sorted in each partition; that will be done on the reduce side // if the operation being run is sortByKey. new ExternalSorter[K, V, V]( context, aggregator = None, Some(dep.partitioner), ordering = None, dep.serializer) } sorter.insertAll(records) // Don't bother including the time to open the merged output file in the shuffle write time, // because it just opens a single file, so is typically too fast to measure accurately // (see SPARK-3570). val output = shuffleBlockResolver.getDataFile(dep.shuffleId, mapId) val tmp = Utils.tempFileWith(output) try { val blockId = ShuffleBlockId(dep.shuffleId, mapId, IndexShuffleBlockResolver.NOOP_REDUCE_ID) val partitionLengths = sorter.writePartitionedFile(blockId, tmp) shuffleBlockResolver.writeIndexFileAndCommit(dep.shuffleId, mapId, partitionLengths, tmp) mapStatus = MapStatus(blockManager.shuffleServerId, partitionLengths) } finally { if (tmp.exists() && !tmp.delete()) { logError(s"Error while deleting temp file ${tmp.getAbsolutePath}") } } }ExternalSorter.insertAll()方法该方法会把迭代器records中的数据插入到外部排序对象中ExternalSorter中的数据是不进行排序的,是以数组的形式存储的,健存的为(partition,key),值为Shuffle之前的RDD链计算结果 在内存中会对相同的key,进行合并操作,就是map端本地合并,合并的函数就是reduceByKey(+)这个算子中定义的函数maybeSpillCollection方法会判断是否满足磁盘溢出到临时文件,满足条件,会把当前内存中的数据写到磁盘中,写到磁盘中的数据是按partition升序排序,再按key升序排序,就是(key,value)的临时文件,不带partition,但是会记录每个分区的数量elementsPerPartition(partitionId- 记录每一次Flush的数据大小batchSizes入到ArrayBuffer中保存内存中的数据存在PartitionedAppendOnlyMap,记住这个对象,后面排序用到了这个里边的排序算法@volatile private var map = new PartitionedAppendOnlyMap[K, C] def insertAll(records: Iterator[Product2[K, V]]): Unit = { // TODO: stop combining if we find that the reduction factor isn't high val shouldCombine = aggregator.isDefined if (shouldCombine) { // Combine values in-memory first using our AppendOnlyMap val mergeValue = aggregator.get.mergeValue val createCombiner = aggregator.get.createCombiner var kv: Product2[K, V] = null val update = (hadValue: Boolean, oldValue: C) => { if (hadValue) mergeValue(oldValue, kv._2) else createCombiner(kv._2) } while (records.hasNext) { addElementsRead() kv = records.next() map.changeValue((getPartition(kv._1), kv._1), update) maybeSpillCollection(usingMap = true) } } else { // Stick values into our buffer while (records.hasNext) { addElementsRead() val kv = records.next() buffer.insert(getPartition(kv._1), kv._1, kv._2.asInstanceOf[C]) maybeSpillCollection(usingMap = false) } } } ExternalSorter.maybeSpillCollectionestimatedSize当前内存中数据预估占内存大小maybeSpill满足Spill条件就把内存中的数据写入到临时文件中调用ExternalSorter.maybeSpill()/** Spill the current in-memory collection to disk if needed.* @param usingMap whether we're using a map or buffer as our current in-memory collection*/ private def maybeSpillCollection(usingMap: Boolean): Unit = { var estimatedSize = 0L if (usingMap) { estimatedSize = map.estimateSize() if (maybeSpill(map, estimatedSize)) { map = new PartitionedAppendOnlyMap[K, C] } } else { estimatedSize = buffer.estimateSize() if (maybeSpill(buffer, estimatedSize)) { buffer = new PartitionedPairBuffer[K, C] } } if (estimatedSize > _peakMemoryUsedBytes) { _peakMemoryUsedBytes = estimatedSize } }ExternalSorter.maybeSpill()对内存中的数据遍历时,每遍历32个元素,进行判断,当前内存是否大于5m,如果大于5m,再进行内存的计算,如果满足就把内存中的数据写到临时文件中如果满足条件,调用ExternalSorter.spill()方法,将内存中的数据写入临时文件 /** Spills the current in-memory collection to disk if needed. Attempts to acquire more memory before spilling.* @param collection collection to spill to disk @param currentMemory estimated size of the collection in bytes @return true if collection was spilled to disk; false otherwise*/ protected def maybeSpill(collection: C, currentMemory: Long): Boolean = { var shouldSpill = false if (elementsRead % 32 == 0 && currentMemory >= myMemoryThreshold) { // Claim up to double our current memory from the shuffle memory pool val amountToRequest = 2 * currentMemory - myMemoryThreshold val granted = acquireOnHeapMemory(amountToRequest) myMemoryThreshold += granted // If we were granted too little memory to grow further (either tryToAcquire returned 0, // or we already had more memory than myMemoryThreshold), spill the current collection shouldSpill = currentMemory >= myMemoryThreshold } shouldSpill = shouldSpill || _elementsRead > numElementsForceSpillThreshold // Actually spill if (shouldSpill) { _spillCount += 1 logSpillage(currentMemory) spill(collection) _elementsRead = 0 _memoryBytesSpilled += currentMemory releaseMemory() } shouldSpill } ExternalSorter.spill()调用方法collection.destructiveSortedWritablePartitionedIterator进行排序,即调用PartitionedAppendOnlyMap.destructiveSortedWritablePartitionedIterator进行排序()方法排序,最终会调用WritablePartitionedPairCollection.destructiveSortedWritablePartitionedIterator()排序,调用方法WritablePartitionedPairCollection.partitionedDestructiveSortedIterator(),没有实现,调用子类PartitionedAppendOnlyMap.partitionedDestructiveSortedIterator()方法调用方法ExternalSorter.spillMemoryIteratorToDisk() 将磁盘中的数据写入到spillFile临时文件中 /** Spill our in-memory collection to a sorted file that we can merge later. We add this file into spilledFiles to find it later.* @param collection whichever collection we're using (map or buffer)*/ override protected[this] def spill(collection: WritablePartitionedPairCollection[K, C]): Unit = { val inMemoryIterator = collection.destructiveSortedWritablePartitionedIterator(comparator) val spillFile = spillMemoryIteratorToDisk(inMemoryIterator) spills.append(spillFile) }PartitionedAppendOnlyMap.partitionedDestructiveSortedIterator()调用排序算法WritablePartitionedPairCollection.partitionKeyComparator即先按分区数的升序排序,再按key的升序排序/** Implementation of WritablePartitionedPairCollection that wraps a map in which the keys are tuples of (partition ID, K)*/ private[spark] class PartitionedAppendOnlyMap[K, V] extends SizeTrackingAppendOnlyMap[(Int, K), V] with WritablePartitionedPairCollection[K, V] { def partitionedDestructiveSortedIterator(keyComparator: Option[Comparator[K]]) : Iterator[((Int, K), V)] = { val comparator = keyComparator.map(partitionKeyComparator).getOrElse(partitionComparator) destructiveSortedIterator(comparator) } def insert(partition: Int, key: K, value: V): Unit = { update((partition, key), value) }} /** A comparator for (Int, K) pairs that orders them both by their partition ID and a key ordering.*/ def partitionKeyComparatorK: Comparator[(Int, K)] = { new Comparator[(Int, K)] { override def compare(a: (Int, K), b: (Int, K)): Int = { val partitionDiff = a._1 - b._1 if (partitionDiff != 0) { partitionDiff } else { keyComparator.compare(a._2, b._2) } } } }}ExternalSorter.spillMemoryIteratorToDisk()创建blockId : temp_shuffle_ + UUID溢出到磁盘临时文件: temp_shuffle_ + UUID遍历内存数据inMemoryIterator写入到磁盘临时文件spillFile遍历内存中的数据写入到临时文件,会记录每个临时文件中每个分区的(key,value)各有多少个,elementsPerPartition(partitionId) 如果说数据很大的话,会每默认每10000条数据进行Flush()一次数据到文件中,会记录每一次Flush的数据大小batchSizes入到ArrayBuffer中保存/** Spill contents of in-memory iterator to a temporary file on disk.*/ private[this] def spillMemoryIteratorToDisk(inMemoryIterator: WritablePartitionedIterator) : SpilledFile = { // Because these files may be read during shuffle, their compression must be controlled by // spark.shuffle.compress instead of spark.shuffle.spill.compress, so we need to use // createTempShuffleBlock here; see SPARK-3426 for more context. val (blockId, file) = diskBlockManager.createTempShuffleBlock() // These variables are reset after each flush var objectsWritten: Long = 0 var spillMetrics: ShuffleWriteMetrics = null var writer: DiskBlockObjectWriter = null def openWriter(): Unit = { assert (writer == null && spillMetrics == null) spillMetrics = new ShuffleWriteMetrics writer = blockManager.getDiskWriter(blockId, file, serInstance, fileBufferSize, spillMetrics) } openWriter() // List of batch sizes (bytes) in the order they are written to disk val batchSizes = new ArrayBuffer[Long] // How many elements we have in each partition val elementsPerPartition = new Array[Long](numPartitions) // Flush the disk writer's contents to disk, and update relevant variables. // The writer is closed at the end of this process, and cannot be reused. def flush(): Unit = { val w = writer writer = null w.commitAndClose() _diskBytesSpilled += spillMetrics.shuffleBytesWritten batchSizes.append(spillMetrics.shuffleBytesWritten) spillMetrics = null objectsWritten = 0 } var success = false try { while (inMemoryIterator.hasNext) { val partitionId = inMemoryIterator.nextPartition() require(partitionId >= 0 && partitionId < numPartitions, s"partition Id: ${partitionId} should be in the range [0, ${numPartitions})") inMemoryIterator.writeNext(writer) elementsPerPartition(partitionId) += 1 objectsWritten += 1 if (objectsWritten == serializerBatchSize) { flush() openWriter() } } if (objectsWritten > 0) { flush() } else if (writer != null) { val w = writer writer = null w.revertPartialWritesAndClose() } success = true } finally { if (!success) { // This code path only happens if an exception was thrown above before we set success; // close our stuff and let the exception be thrown further if (writer != null) { writer.revertPartialWritesAndClose() } if (file.exists()) { if (!file.delete()) { logWarning(s"Error deleting ${file}") } } } } SpilledFile(file, blockId, batchSizes.toArray, elementsPerPartition) } 源码分析(内存数据Spill合并)SortShuffleWriter.insertAll即内存中的数据,如果有溢出,写入到临时文件后,可能会有多个临时文件(看数据的大小) 这时要开始从所有的临时文件中,shuffle出按给reduce输入数据(partition,Iterator),相当于要对多个临时文件进行合成一个文件,合成的结果按partition升序排序,再按Key升序排序 SortShuffleWriter.write 得到合成文件shuffleBlockResolver.getDataFile : 格式如 "shuffle_" + shuffleId + "" + mapId + "" + reduceId + ".data" + "." + UUID,reduceId为默认的0 调用关键方法ExternalSorter的sorter.writePartitionedFile,这才是真正合成文件的方法 返回值partitionLengths,即为数据文件中对应索引文件按分区从0到最大分区,每个分区的数据大小的数组 /* Write a bunch of records to this task's output / override def write(records: Iterator[Product2[K, V]]): Unit = { sorter = if (dep.mapSideCombine) { require(dep.aggregator.isDefined, "Map-side combine without Aggregator specified!") new ExternalSorter[K, V, C]( context, dep.aggregator, Some(dep.partitioner), dep.keyOrdering, dep.serializer) } else { // In this case we pass neither an aggregator nor an ordering to the sorter, because we don't // care whether the keys get sorted in each partition; that will be done on the reduce side // if the operation being run is sortByKey. new ExternalSorter[K, V, V]( context, aggregator = None, Some(dep.partitioner), ordering = None, dep.serializer) } sorter.insertAll(records) // Don't bother including the time to open the merged output file in the shuffle write time, // because it just opens a single file, so is typically too fast to measure accurately // (see SPARK-3570). val output = shuffleBlockResolver.getDataFile(dep.shuffleId, mapId) val tmp = Utils.tempFileWith(output) try { val blockId = ShuffleBlockId(dep.shuffleId, mapId, IndexShuffleBlockResolver.NOOP_REDUCE_ID) val partitionLengths = sorter.writePartitionedFile(blockId, tmp) shuffleBlockResolver.writeIndexFileAndCommit(dep.shuffleId, mapId, partitionLengths, tmp) mapStatus = MapStatus(blockManager.shuffleServerId, partitionLengths) } finally { if (tmp.exists() && !tmp.delete()) { logError(s"Error while deleting temp file ${tmp.getAbsolutePath}") } } } ExternalSorter.writePartitionedFile按方法名直译,把数据写入已分区的文件中如果没有spill文件,直接按ExternalSorter在内存中排序,用的是TimSort排序算法排序,单独合出来讲,这里不详细讲如果有spill文件,是我们重点分析的,这个时候,调用this.partitionedIterator按回按[(partition,Iterator)],按分区升序排序,按(key,value)中key升序排序的数据,并键中方法this.partitionedIterator()写入合并文件中,并返回写入合并文件中每个分区的长度,放到lengths数组中,数组索引就是partition/** Write all the data added into this ExternalSorter into a file in the disk store. This is called by the SortShuffleWriter.* @param blockId block ID to write to. The index file will be blockId.name + ".index". @return array of lengths, in bytes, of each partition of the file (used by map output tracker)*/ def writePartitionedFile( blockId: BlockId, outputFile: File): Array[Long] = { // Track location of each range in the output file val lengths = new Array[Long](numPartitions) if (spills.isEmpty) { // Case where we only have in-memory data val collection = if (aggregator.isDefined) map else buffer val it = collection.destructiveSortedWritablePartitionedIterator(comparator) while (it.hasNext) { val writer = blockManager.getDiskWriter(blockId, outputFile, serInstance, fileBufferSize, context.taskMetrics.shuffleWriteMetrics.get) val partitionId = it.nextPartition() while (it.hasNext && it.nextPartition() == partitionId) { it.writeNext(writer) } writer.commitAndClose() val segment = writer.fileSegment() lengths(partitionId) = segment.length } } else { // We must perform merge-sort; get an iterator by partition and write everything directly. for ((id, elements) <- this.partitionedIterator) { if (elements.hasNext) { val writer = blockManager.getDiskWriter(blockId, outputFile, serInstance, fileBufferSize, context.taskMetrics.shuffleWriteMetrics.get) for (elem <- elements) { writer.write(elem._1, elem._2) } writer.commitAndClose() val segment = writer.fileSegment() lengths(id) = segment.length } } } context.taskMetrics().incMemoryBytesSpilled(memoryBytesSpilled) context.taskMetrics().incDiskBytesSpilled(diskBytesSpilled) context.internalMetricsToAccumulators( InternalAccumulator.PEAK_EXECUTION_MEMORY).add(peakMemoryUsedBytes) lengths } this.partitionedIterator()直接调用ExternalSorter.merge()方法临时文件参数spills内存文件排序算法在这里调用collection.partitionedDestructiveSortedIterator(comparator),实际调的是PartitionedAppendOnlyMap.partitionedDestructiveSortedIterator,定义了排序算法partitionKeyComparator,即按partition升序排序,再按key升序排序/** Return an iterator over all the data written to this object, grouped by partition and aggregated by the requested aggregator. For each partition we then have an iterator over its contents, and these are expected to be accessed in order (you can't "skip ahead" to one partition without reading the previous one). Guaranteed to return a key-value pair for each partition, in order of partition ID.* For now, we just merge all the spilled files in once pass, but this can be modified to support hierarchical merging. Exposed for testing.*/ def partitionedIterator: Iterator[(Int, Iterator[Product2[K, C]])] = { val usingMap = aggregator.isDefined val collection: WritablePartitionedPairCollection[K, C] = if (usingMap) map else buffer if (spills.isEmpty) { // Special case: if we have only in-memory data, we don't need to merge streams, and perhaps // we don't even need to sort by anything other than partition ID if (!ordering.isDefined) { // The user hasn't requested sorted keys, so only sort by partition ID, not key groupByPartition(destructiveIterator(collection.partitionedDestructiveSortedIterator(None))) } else { // We do need to sort by both partition ID and key groupByPartition(destructiveIterator( collection.partitionedDestructiveSortedIterator(Some(keyComparator)))) } } else { // Merge spilled and in-memory data merge(spills, destructiveIterator( collection.partitionedDestructiveSortedIterator(comparator))) } } ExternalSorter.merge()方法0 until numPartitions 从0到numPartitions(不包含)分区循环调用IteratorForPartition(p, inMemBuffered),每次取内存中的p分区的数据readers是每个分区是读所有的临时文件(因为每份临时文件,都有可能包含p分区的数据),readers.map(_.readNextPartition())该方法内部用的是每次调一个分区的数据,从0开始,刚好对应的是p分区的数据readNextPartition方法即调用SpillReader.readNextPartition()方法对p分区的数据进行mergeWithAggregation合并后,再写入到合并文件中 /** Merge a sequence of sorted files, giving an iterator over partitions and then over elements inside each partition. This can be used to either write out a new file or return data to the user.* Returns an iterator over all the data written to this object, grouped by partition. For each partition we then have an iterator over its contents, and these are expected to be accessed in order (you can't "skip ahead" to one partition without reading the previous one). Guaranteed to return a key-value pair for each partition, in order of partition ID.*/ private def merge(spills: Seq[SpilledFile], inMemory: Iterator[((Int, K), C)]) : Iterator[(Int, Iterator[Product2[K, C]])] = { val readers = spills.map(new SpillReader(_)) val inMemBuffered = inMemory.buffered (0 until numPartitions).iterator.map { p => val inMemIterator = new IteratorForPartition(p, inMemBuffered) val iterators = readers.map(_.readNextPartition()) ++ Seq(inMemIterator) if (aggregator.isDefined) { // Perform partial aggregation across partitions (p, mergeWithAggregation( iterators, aggregator.get.mergeCombiners, keyComparator, ordering.isDefined)) } else if (ordering.isDefined) { // No aggregator given, but we have an ordering (e.g. used by reduce tasks in sortByKey); // sort the elements without trying to merge them (p, mergeSort(iterators, ordering.get)) } else { (p, iterators.iterator.flatten) } } } SpillReader.readNextPartition()readNextItem()是真正读数临时文件的方法,deserializeStream每次读取一个流大小,这个大小时在spill输出文件时写到batchSizes中的,某个是每个分区写一次流,如果分区中的数据很大,就按10000条数据进行一次流,这样每满10000次就再读一次流,这样就可以把当前分区里边的多少提交流全部读完一进来就执行nextBatchStream()方法,该方法是按数组batchSizes存储着每次写入流时的数据大小val batchOffsets = spill.serializerBatchSizes.scanLeft(0L)(_ + _)这个其实取到的值,就刚好是每次流的一位置偏移量,后面的偏移量,刚好是前面所有偏移量之和当前分区的流读完时,就为空,就相当于当前分区的数据全部读完了当partitionId=numPartitions,finished= true说明所有分区的所有文件全部读完了def readNextPartition(): Iterator[Product2[K, C]] = new Iterator[Product2[K, C]] { val myPartition = nextPartitionToRead nextPartitionToRead += 1 override def hasNext: Boolean = { if (nextItem == null) { nextItem = readNextItem() if (nextItem == null) { return false } } assert(lastPartitionId >= myPartition) // Check that we're still in the right partition; note that readNextItem will have returned // null at EOF above so we would've returned false there lastPartitionId == myPartition } override def next(): Product2[K, C] = { if (!hasNext) { throw new NoSuchElementException } val item = nextItem nextItem = null item } } /** * Return the next (K, C) pair from the deserialization stream and update partitionId, * indexInPartition, indexInBatch and such to match its location. * * If the current batch is drained, construct a stream for the next batch and read from it. * If no more pairs are left, return null. */ private def readNextItem(): (K, C) = { if (finished || deserializeStream == null) { return null } val k = deserializeStream.readKey().asInstanceOf[K] val c = deserializeStream.readValue().asInstanceOf[C] lastPartitionId = partitionId // Start reading the next batch if we're done with this one indexInBatch += 1 if (indexInBatch == serializerBatchSize) { indexInBatch = 0 deserializeStream = nextBatchStream() } // Update the partition location of the element we're reading indexInPartition += 1 skipToNextPartition() // If we've finished reading the last partition, remember that we're done if (partitionId == numPartitions) { finished = true if (deserializeStream != null) { deserializeStream.close() } } (k, c) } /* Construct a stream that only reads from the next batch / def nextBatchStream(): DeserializationStream = { // Note that batchOffsets.length = numBatches + 1 since we did a scan above; check whether // we're still in a valid batch. if (batchId < batchOffsets.length - 1) { if (deserializeStream != null) { deserializeStream.close() fileStream.close() deserializeStream = null fileStream = null } val start = batchOffsets(batchId) fileStream = new FileInputStream(spill.file) fileStream.getChannel.position(start) batchId += 1 val end = batchOffsets(batchId) assert(end >= start, "start = " + start + ", end = " + end + ", batchOffsets = " + batchOffsets.mkString("[", ", ", "]")) val bufferedStream = new BufferedInputStream(ByteStreams.limit(fileStream, end - start)) val sparkConf = SparkEnv.get.conf val stream = blockManager.wrapForCompression(spill.blockId, CryptoStreamUtils.wrapForEncryption(bufferedStream, sparkConf)) serInstance.deserializeStream(stream) } else { // No more batches left cleanup() null } } end
thinktothings 2019-12-02 01:47:56 0 浏览量 回答数 0

回答

1.使用key值前缀来作命名空间虽然说Redis支持多个数据库(默认32个,可以配置更多),但是除了默认的0号库以外,其它的都需要通过一个额外请求才能使用。所以用前缀作为命名空间可能会更明智一点。另外,在使用前缀作为命名空间区隔不同key的时候,最好在程序中使用全局配置来实现,直接在代码里写前缀的做法要严格避免,这样可维护性实在太差了。2.创建一个类似 ”registry” 的key用于标记key使用情况为了更好的管理你的key值的使用,比如哪一类key值是属于哪个业务的,你通常会在内部wiki或者什么地方创建一个文档,通过查询这个文档,我们能够知道Redis中的key都是什么作用。与之结合,一个推荐的做法是,在Redis里面保存一个registry值,这个值的名字可以类似于 key_registry 这样的,这个key对应的value就是你文档的位置,这样我们在使用Redis的时候,就能通过直接查询这个值获取到当前Redis的使用情况了。3.注意垃圾回收Redis是一个提供持久化功能的内存数据库,如果你不指定上面值的过期时间,并且也不进行定期的清理工作,那么你的Redis内存占用会越来越大,当有一天它超过了系统可用内存,那么swap上场,离性能陡降的时间就不远了。所以在Redis中保存数据时,一定要预先考虑好数据的生命周期,这有很多方法可以实现。比如你可以采用Redis自带的过期时间为你的数据设定过期时间。但是自动过期有一个问题,很有可能导致你还有大量内存可用时,就让key过期去释放内存,或者是内存已经不足了key还没有过期。如果你想更精准的控制你的数据过期,你可以用一个ZSET来维护你的数据更新程度,你可以用时间戳作为score值,每次更新操作时更新一下score,这样你就得到了一个按更新时间排序序列串,你可以轻松地找到最老的数据,并且从最老的数据开始进行删除,一直删除到你的空间足够为止。4.设计好你的Sharding机制Redis目前并不支持Sharding,但是当你的数据量超过单机内存时,你不得不考虑Sharding的事(注意:Slave不是用来做Sharding操作的,只是数据的一个备份和读写分离而已)。所以你可能需要考虑好数据量大了后的分片问题,比如你可以在只有一台机器的时候就在程序上设定一致性hash机制,虽然刚开始所有数据都hash到一台机器,但是当你机器越加越多的时候,你就只需要迁移少量的数据就能完成了。5.不要有个锤子看哪都是钉子当你使用Redis构建你的服务的时候,一定要记住,你只是找了一个合适的工具来实现你需要的功能。而不是说你在用Redis构建一个服务,这是很不同的,你把Redis当作你很多工具中的一个,只在合适使用的时候再使用它,在不合适的时候选择其它的方法。
落地花开啦 2019-12-02 01:48:56 0 浏览量 回答数 0

问题

TableInBatchGetRowRequest

在 BatchGetRow 操作中,表示要读取的一个表的请求信息。 数据结构message TableInBatchGetRowRequest {    required string table_name = 1...
云栖大讲堂 2019-12-01 21:01:41 1444 浏览量 回答数 0

回答

第一步:我数据库备份某目录注明间: 运行备份脚本(注意备份目录我/home/dbback/) 查看目录否备份文件细同能发现我mysqldump没指定用户名密码啥我运行候费用输入密码呢莫着急马揭晓答案mysql5.6(具体版本编号记)密码写脚本运行警告告诉要密码写脚本危险我伙伴该办呢官给解决案期望配置my.cnf文件所现打my.cnf加入字段: 两条运行脚本提示要输入密码马测试看否功没问题我进入步 第二步:何自备份oss始前我要做两件事 1、登录阿云控制台点右管理控制台点左产品与服务第二列点击象存储OSS没通要通通直接点击右新建bucket创建bucket记住buket名字(注:其实通api直接创建bucket操作所我用控制台创建降低理解难度) 2、始写传脚本要导入osssdk所要安装比较简单跟安装其python包没啥区别解压进入目录运行python setup.py install 安装完毕接看我何使用全部代码: #!/usr/bin/python env #autor:glacier #date:2015-11-16 import os,os.path,time import operator import time from oss.oss_api import * prefix = '/home/dbback' logtime = time.strftime(time.ctime()) #filelist = [ file for file in os.listdir(os.path.dirname(os.path.abspath(file))) if os.path.isfile(file) ] filelist = [ file for file in os.listdir(prefix) if os.path.isfile(prefix + '/' + file) ] def get_time(filename): ft = os.stat(filename) return ft.st_ctime #def get_max(): # flist = [] # for file in filelist: # flist.append(os.stat(file).st_ctime) # return max(flist) def get_dist(): d = {} for file in filelist: d[file] = get_time(prefix + '/' + file) return d if name == 'main': #maxtime = get_max() d = get_dist() #dic= sorted(d.iteritems(), key=lambda d:d[1], reverse = True) upfile = max(d.iteritems(), key=operator.itemgetter(1))[0] endpoint = "your aliyun endpoint" accessKeyId, accessKeySecret="your accessKeyId","your accessKeySecret " oss = OssAPI(endpoint, accessKeyId, accessKeySecret) res = oss.put_object_from_file("bucketname",upfile,prefix + '/' + upfile) if res.status != 200: with open('/var/log/dbback.log', 'a+') as f: f.write(logtime + ' back failed' + '\n') 我接析脚本内容其脚本注释行都用看我编写程测试用始我设定备份文件目录记录志间备份目录所文件列表(列表其实式我用简单式文件列表慢)定义两函数get_time()函数获取文件创建间戳get_dist()函数获取文件名间戳字典主函数部比较难理解根据字典value排序获文件名d.iteritems()获字典每key,valuekey指定函数operator.itemgetter(1)表示用value排序(两元素key 0value1)间戳排序完返key[0]做工作脚本其部内容我说都见用没难于理解脚本介绍接进入我步 第三步:脚本写入crontab具体候执行根据家各自业务同设置没特别 答案来源网络,供参考,希望对您有帮助
KB小秘书 2019-12-02 03:00:11 0 浏览量 回答数 0

问题

JavaSDK的搜索如何操作?(8)

添加统计信息(aggregate)相关参数(2) 参数描述 参数名称类型描述groupKeyString指定需要统计的字段名称。aggFunString指定统计的方法。当前支持:count、max、min、sum等...
轩墨 2019-12-01 20:58:20 1073 浏览量 回答数 0

回答

首先给你个忠告永远不要省略if for while等语句的大括号 然后 一行只写一句话 最后 具体的错误等稍后我看过代码再给出 ###### 递归爆炸了,改成循环吧 ######数据不大 可以使用递归  ,数据大了 会出现栈溢出,因为在没有分支结束前或者被强行中断,单个线程是不会释放栈现场的。1.修改栈大小 。2.采用非递归方式。----几乎各个语言都要避免下这个问题哦######应该需要修改编译器堆栈的大小,但没有实际尝试,可以先修改N的大小,看是否堆栈还溢出。是否还有其他错误。######递归函数中没有一个return,递归调用还在必经路径上——连编译器都知道它会归死。######回复 @zhangjihan10 : 模拟一个栈 加上goto语句 就比较简单了 不过代码还是会很乱######回复 @zhangjihan10 : 当然可以, 自己模拟一个栈就可以了, 但是这有什么意义呢?######回复 @猫咪喵喵 :没递归结束条件呀,你能用循环写出来吗######回复 @猫咪喵喵 : 你是怎么贴出带有行号和滚动条这种效果的######然后统计时间的时候居然把数据准备 打印输出结果都算进去 真是乱的可以###### 简单看了一下你的代码 你的代码确实会栈溢出 这源于你并没有指定结束递归的条件 ###### 试试看这个 #include<stdio.h> #include<stdlib.h> #include<time.h> #define N 1000 void quick_sort(int a[], int start, int end) { int i = start, j = end; int key = a[i]; while(i < j) { for(; i < j; j--) { if(a[j] < key) { a[i++] = a[j]; break; } } for(; i < j; i++) { if(a[i] > key) { a[j--] = a[i]; break; } } } a[i] = key; if(start < i - 1){ quick_sort(a, start, i - 1); } if(end > i + 1){ quick_sort(a, i + 1, end); } } int main() { srand((unsigned)time(NULL)); //随机数种子准备 int array[N] = {0}; //要被排序的数据准备 for(int i = 0; i < N; i++){ //随机生成一些数据 array[i] = rand() % N; } clock_t start = clock(); //记录开始时间 quick_sort(array, 0, 999); //调用排序算法对数据进行排序 clock_t end = clock(); //记录结束时间 for(int i = 0; i < N; i++){ //打印输出排序后的数据 printf("%5d", array[i]); } printf("\n"); double t = (double)(end - start) / CLOCKS_PER_SEC; //计算算法所消耗的时间 printf("快速排序运行时间:%lf秒\n", t); //输出时间 return 0; } ######回复 @月光双刀 : 仔细看提问者的代码 溢出并不是因为数据量过大 而是他的代码有问题 所以说 这个可以解决问题######这个也会栈溢出######编辑器上有个插入代码或脚本啦 @zhangjihan10######回复 @zhangjihan10 : 。######求大神手把手教代码高亮使用方法
kun坤 2020-06-14 12:17:32 0 浏览量 回答数 0

回答

首先给你个忠告永远不要省略if for while等语句的大括号 然后 一行只写一句话 最后 具体的错误等稍后我看过代码再给出 ###### 递归爆炸了,改成循环吧 ######数据不大 可以使用递归  ,数据大了 会出现栈溢出,因为在没有分支结束前或者被强行中断,单个线程是不会释放栈现场的。1.修改栈大小 。2.采用非递归方式。----几乎各个语言都要避免下这个问题哦######应该需要修改编译器堆栈的大小,但没有实际尝试,可以先修改N的大小,看是否堆栈还溢出。是否还有其他错误。######递归函数中没有一个return,递归调用还在必经路径上——连编译器都知道它会归死。######回复 @zhangjihan10 : 模拟一个栈 加上goto语句 就比较简单了 不过代码还是会很乱######回复 @zhangjihan10 : 当然可以, 自己模拟一个栈就可以了, 但是这有什么意义呢?######回复 @猫咪喵喵 :没递归结束条件呀,你能用循环写出来吗######回复 @猫咪喵喵 : 你是怎么贴出带有行号和滚动条这种效果的######然后统计时间的时候居然把数据准备 打印输出结果都算进去 真是乱的可以###### 简单看了一下你的代码 你的代码确实会栈溢出 这源于你并没有指定结束递归的条件 ###### 试试看这个 #include<stdio.h> #include<stdlib.h> #include<time.h> #define N 1000 void quick_sort(int a[], int start, int end) { int i = start, j = end; int key = a[i]; while(i < j) { for(; i < j; j--) { if(a[j] < key) { a[i++] = a[j]; break; } } for(; i < j; i++) { if(a[i] > key) { a[j--] = a[i]; break; } } } a[i] = key; if(start < i - 1){ quick_sort(a, start, i - 1); } if(end > i + 1){ quick_sort(a, i + 1, end); } } int main() { srand((unsigned)time(NULL)); //随机数种子准备 int array[N] = {0}; //要被排序的数据准备 for(int i = 0; i < N; i++){ //随机生成一些数据 array[i] = rand() % N; } clock_t start = clock(); //记录开始时间 quick_sort(array, 0, 999); //调用排序算法对数据进行排序 clock_t end = clock(); //记录结束时间 for(int i = 0; i < N; i++){ //打印输出排序后的数据 printf("%5d", array[i]); } printf("\n"); double t = (double)(end - start) / CLOCKS_PER_SEC; //计算算法所消耗的时间 printf("快速排序运行时间:%lf秒\n", t); //输出时间 return 0; } ######回复 @月光双刀 : 仔细看提问者的代码 溢出并不是因为数据量过大 而是他的代码有问题 所以说 这个可以解决问题######这个也会栈溢出######编辑器上有个插入代码或脚本啦 @zhangjihan10######回复 @zhangjihan10 : 。######求大神手把手教代码高亮使用方法
kun坤 2020-06-02 14:30:33 0 浏览量 回答数 0

问题

PhpSDK的搜索如何操作?(16)

添加distinct排序信息 例如:检索关键词“手机”共获得10个结果,分别为:doc1,doc2,doc3,doc4,doc5ÿ...
轩墨 2019-12-01 20:58:56 1111 浏览量 回答数 0

回答

" 首先给你个忠告永远不要省略if for while等语句的大括号 然后 一行只写一句话 最后 具体的错误等稍后我看过代码再给出 ###### 递归爆炸了,改成循环吧 ######数据不大 可以使用递归  ,数据大了 会出现栈溢出,因为在没有分支结束前或者被强行中断,单个线程是不会释放栈现场的。1.修改栈大小 。2.采用非递归方式。----几乎各个语言都要避免下这个问题哦######应该需要修改编译器堆栈的大小,但没有实际尝试,可以先修改N的大小,看是否堆栈还溢出。是否还有其他错误。######递归函数中没有一个return,递归调用还在必经路径上——连编译器都知道它会归死。######回复 @zhangjihan10 : 模拟一个栈 加上goto语句 就比较简单了 不过代码还是会很乱######回复 @zhangjihan10 : 当然可以, 自己模拟一个栈就可以了, 但是这有什么意义呢?######回复 @猫咪喵喵 :没递归结束条件呀,你能用循环写出来吗######回复 @猫咪喵喵 : 你是怎么贴出带有行号和滚动条这种效果的######然后统计时间的时候居然把数据准备 打印输出结果都算进去 真是乱的可以###### 简单看了一下你的代码 你的代码确实会栈溢出 这源于你并没有指定结束递归的条件 ###### 试试看这个 #include<stdio.h> #include<stdlib.h> #include<time.h> #define N 1000 void quick_sort(int a[], int start, int end) { int i = start, j = end; int key = a[i]; while(i < j) { for(; i < j; j--) { if(a[j] < key) { a[i++] = a[j]; break; } } for(; i < j; i++) { if(a[i] > key) { a[j--] = a[i]; break; } } } a[i] = key; if(start < i - 1){ quick_sort(a, start, i - 1); } if(end > i + 1){ quick_sort(a, i + 1, end); } } int main() { srand((unsigned)time(NULL)); //随机数种子准备 int array[N] = {0}; //要被排序的数据准备 for(int i = 0; i < N; i++){ //随机生成一些数据 array[i] = rand() % N; } clock_t start = clock(); //记录开始时间 quick_sort(array, 0, 999); //调用排序算法对数据进行排序 clock_t end = clock(); //记录结束时间 for(int i = 0; i < N; i++){ //打印输出排序后的数据 printf("%5d", array[i]); } printf("\n"); double t = (double)(end - start) / CLOCKS_PER_SEC; //计算算法所消耗的时间 printf("快速排序运行时间:%lf秒\n", t); //输出时间 return 0; } ######回复 @月光双刀 : 仔细看提问者的代码 溢出并不是因为数据量过大 而是他的代码有问题 所以说 这个可以解决问题######这个也会栈溢出######编辑器上有个插入代码或脚本啦 @zhangjihan10######回复 @zhangjihan10 : 。######求大神手把手教代码高亮使用方法"
montos 2020-06-03 17:13:17 0 浏览量 回答数 0

回答

索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。 这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。 索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构 createIndex() 方法 MongoDB使用 createIndex() 方法来创建索引。 注意在 3.0.0 版本前创建索引方法为 db.collection.ensureIndex(),之后的版本使用了 db.collection.createIndex() 方法,ensureIndex() 还能用,但只是 createIndex() 的别名。 语法 createIndex()方法基本语法格式如下所示: db.collection.createIndex(keys, options) 语法中 Key 值为你要创建的索引字段,1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1 即可。 实例 db.col.createIndex({"title":1}) createIndex() 方法中你也可以设置使用多个字段创建索引(关系型数据库中称作复合索引)。 db.col.createIndex({"title":1,"description":-1}) createIndex() 接收可选参数,可选参数列表如下: Parameter Type Description background Boolean 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 "background" 可选参数。 "background" 默认值为false。 unique Boolean 建立的索引是否唯一。指定为true创建唯一索引。默认值为false. name string 索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。 dropDups Boolean 3.0+版本已废弃。在建立唯一索引时是否删除重复记录,指定 true 创建唯一索引。默认值为 false. sparse Boolean 对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false. expireAfterSeconds integer 指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。 v index version 索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。 weights document 索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重。 default_language string 对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语 language_override string 对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为 language. 实例 在后台创建索引: db.values.createIndex({open: 1, close: 1}, {background: true}) 通过在创建索引时加 background:true 的选项,让创建工作在后台执行
游客2q7uranxketok 2021-02-08 23:44:12 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档OSSGetBucketRequest * getBucket = [OSSGetBucketRequest new];getBucket.bucketName = @"<bucketName>";// 可选参数,具体含义参考:https://docs.aliyun.com/#/pub/oss/api-reference/bucket&GetBucket// getBucket.marker = @"";// getBucket.prefix = @"";// getBucket.delimiter = @"";OSSTask * getBucketTask = [client getBucket:getBucket];[getBucketTask continueWithBlock:^id(OSSTask *task) { if (!task.error) { OSSGetBucketResult * result = task.result; NSLog(@"get bucket success!"); for (NSDictionary * objectInfo in result.contents) { NSLog(@"list object: %@", objectInfo); } } else { NSLog(@"get bucket failed, error: %@", task.error); } return nil;}]; 罗列操作具体可设置的参数名称和作用如下: 名称 作用 delimiter 用于对Object名字进行分组的字符。所有名字包含指定的前缀且第一次出现delimiter字符之间的object作为一组元素: CommonPrefixes。 marker 设定结果从marker之后按字母排序的第一个开始返回。 maxkeys 限定此次返回object的最大数,如果不设定,默认为100,maxkeys取值不能大于1000。 prefix 限定返回的object key必须以prefix作为前缀。注意使用prefix查询时,返回的key中仍会包含prefix。
2019-12-01 23:14:13 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档OSSGetBucketRequest * getBucket = [OSSGetBucketRequest new];getBucket.bucketName = @"<bucketName>";// 可选参数,具体含义参考:https://docs.aliyun.com/#/pub/oss/api-reference/bucket&GetBucket// getBucket.marker = @"";// getBucket.prefix = @"";// getBucket.delimiter = @"";OSSTask * getBucketTask = [client getBucket:getBucket];[getBucketTask continueWithBlock:^id(OSSTask *task) { if (!task.error) { OSSGetBucketResult * result = task.result; NSLog(@"get bucket success!"); for (NSDictionary * objectInfo in result.contents) { NSLog(@"list object: %@", objectInfo); } } else { NSLog(@"get bucket failed, error: %@", task.error); } return nil;}]; 罗列操作具体可设置的参数名称和作用如下: 名称 作用 delimiter 用于对Object名字进行分组的字符。所有名字包含指定的前缀且第一次出现delimiter字符之间的object作为一组元素: CommonPrefixes。 marker 设定结果从marker之后按字母排序的第一个开始返回。 maxkeys 限定此次返回object的最大数,如果不设定,默认为100,maxkeys取值不能大于1000。 prefix 限定返回的object key必须以prefix作为前缀。注意使用prefix查询时,返回的key中仍会包含prefix。
2019-12-01 23:14:12 0 浏览量 回答数 0

云产品推荐

上海奇点人才服务相关的云产品 小程序定制 上海微企信息技术相关的云产品 国内短信套餐包 ECS云服务器安全配置相关的云产品 开发者问答 阿里云建站 自然场景识别相关的云产品 万网 小程序开发制作 视频内容分析 视频集锦 代理记账服务