Multiset стирает только один экземпляр [дубликат]

Запись данных
  1. Включите применимый драйвер JDBC при отправке приложения или запуске оболочки. Вы можете использовать, например, --packages:
    bin/pyspark --packages group:name:version  
    
    или комбинировать driver-class-path и jars
    bin/pyspark --driver-class-path $PATH_TO_DRIVER_JAR --jars $PATH_TO_DRIVER_JAR
    
    Эти свойства также могут быть установлены с использованием переменной среды PYSPARK_SUBMIT_ARGS до запуска экземпляра JVM или с помощью conf/spark-defaults.conf для установки spark.jars.packages или spark.jars / spark.driver.extraClassPath.
  2. Выберите нужный режим. Писатель Spark JDBC поддерживает следующие режимы: append: добавить содержимое этого: class: DataFrame к существующим данным. overwrite: Перезаписать существующие данные. ignore: тихо игнорируйте эту операцию, если данные уже существуют. error (случай по умолчанию): выдать исключение, если данные уже существуют. Усиления или другие мелкозернистые модификации не поддерживаются
    mode = ...
    
  3. Подготовить URI JDBC, например:
    # You can encode credentials in URI or pass
    # separately using properties argument
    # of jdbc method or options
    
    url = "jdbc:postgresql://localhost/foobar"
    
  4. (Необязательно) Создать словарь аргументов JDBC.
    properties = {
        "user": "foo",
        "password": "bar"
    }
    
  5. Для сохранения данных используйте DataFrame.write.jdbc
    df.write.jdbc(url=url, table="baz", mode=mode, properties=properties)
    
    (подробнее см. pyspark.sql.DataFrameWriter ).

Известные проблемы :

  • Подходящий драйвер не может быть найден, если драйвер был включен с использованием --packages (java.sql.SQLException: No suitable driver found for jdbc: ...) Предполагая, что для решения проблемы нет несоответствия версии драйвера, вы можете добавить класс driver в properties. Например:
    properties = {
        ...
        "driver": "org.postgresql.Driver"
    }
    
  • с помощью df.write.format("jdbc").options(...).save() может привести к: java.lang.RuntimeException: org.apache.spark.sql.execution.datasources.jdbc.DefaultSource не позволяет создавать таблицу как выбранную. Решение неизвестно.
  • в Pyspark 1.3 вы можете попробовать напрямую вызвать метод Java:
    df._jdf.insertIntoJDBC(url, "baz", True)
    

Чтение данных

  1. Выполните шаги 1 -4 из Запись данных
  2. Используйте sqlContext.read.jdbc:
    sqlContext.read.jdbc(url=url, table="baz", properties=properties)
    
    или sqlContext.read.format("jdbc"):
    (sqlContext.read.format("jdbc")
        .options(url=url, dbtable="baz", **properties)
        .load())
    

Известные проблемы и gotchas :

  • Подходящий драйвер не может быть найден - см .: Запись данных
  • Spark SQL поддерживает перенаправление предикатов с источниками JDBC, хотя не все предикаты могут быть сдвинуты вниз. Он также не делегирует ограничения и агрегаты. Возможным обходным решением является замена аргумента dbtable / table действительным подзапросом. См. Например: Работает ли искривление предиката с JDBC? Более одного часа для выполнения pyspark.sql.DataFrame.take (4)
  • By по умолчанию источники данных JDBC загружают данные последовательно, используя один поток исполнителей. Для обеспечения распределенной загрузки данных вы можете: Предоставить разделение column (должно быть IntegeType), lowerBound, upperBound, numPartitions. Предоставьте список взаимоисключающих предикатов predicates, по одному для каждого требуемого раздела.
  • В распределенном режиме (с разделительным столбцом или предикатами) каждый исполнитель работает в своей собственной транзакции. Если исходная база данных изменяется одновременно, нет гарантии, что окончательный вид будет согласован.

Где найти подходящие драйверы:

127
задан stanwise 19 December 2012 в 15:41
поделиться

5 ответов

Стандартный идентификатор стирания ассоциативного контейнера:

for (auto it = m.cbegin(); it != m.cend() /* not hoisted */; /* no increment */)
{
  if (must_delete)
  {
    m.erase(it++);    // or "it = m.erase(it)" since C++11
  }
  else
  {
    ++it;
  }
}

Обратите внимание, что мы действительно хотим, чтобы обычный for цикл здесь, так как мы модифицируем сам контейнер. Цикл, основанный на диапазоне, должен быть строго зарезервирован для ситуаций, когда мы заботимся только об элементах. Синтаксис RBFL делает это ясным, даже не подвергая контейнер внутри тела цикла.

Редактировать. Pre-C ++ 11, вы не могли стереть константы-константы. Там вы должны сказать:

for (std::map<K,V>::iterator it = m.begin(); it != m.end(); ) { /* ... */ }

Стирание элемента из контейнера не противоречит константе элемента. По аналогии, он всегда был совершенно законным delete p, где p является указателем на константу. Константа не ограничивает время жизни; константы в C ++ все еще могут перестать существовать.

201
ответ дан Kerrek SB 19 August 2018 в 12:18
поделиться
  • 1
    «даже не подвергая контейнер внутри корпуса петли», что вы имеете в виду? – Dani 23 November 2011 в 00:34
  • 2
    @ Дани: Хорошо, это контрастирует с конструкцией 20-го века for (int i = 0; i < v.size(); i++). Здесь мы должны сказать v[i] внутри цикла, т. Е. Мы должны явно указать контейнер. RBFL, с другой стороны, вводит переменную цикла, которая непосредственно используется в качестве значения, и поэтому внутри цикла не требуется знание контейнера. Это ключ к предполагаемому использованию циклов RBFL для циклов, которые not должны знать о контейнере. Стирание - это полная противоположная ситуация, когда речь идет о контейнере. – Kerrek SB 23 November 2011 в 00:41
  • 3
    @skyhisi: Просто увидел себя и исправил, спасибо! Я смешался с ним в идиоме последовательности, где вы говорите it = v.erase(it); (нет ++). Это никогда не повторится, обещание. – Kerrek SB 23 November 2011 в 00:43
  • 4
  • 5
    Я где-то читал, что в C ++ 11 it = v.erase(it); теперь тоже работает для карт. То есть, ассоциация erase () on all теперь возвращает следующий итератор. Таким образом, старый kludge, который потребовал post-increment ++ в delete (), больше не нужен. Это (если это правда) - это хорошая вещь, поскольку kludge полагался на магию с переопределенным постом-инкрементом внутри функции, «фиксированную». новичкам-сопровождающим, чтобы получить прирост из вызова функции, или поменять его на предустановление », потому что это всего лишь вещь стиля» и т. д. – Dewi Morgan 30 January 2015 в 00:11

Я лично предпочитаю этот шаблон, который немного яснее и проще, за счет дополнительной переменной:

for (auto it = m.cbegin(), next_it = m.cbegin(); it != m.cend(); it = next_it)
{
  next_it = it; ++next_it;
  if (must_delete)
  {
    m.erase(it);
  }
}

Преимущества этого подхода:

  • для инкрементер цикла имеет смысл в качестве инкрементора;
  • операция стирания - это простое удаление, а не смешивание с логикой нарастания;
  • после первой строки тела цикла значение из it и next_it остаются фиксированными на протяжении всей итерации, что позволяет вам легко добавлять дополнительные инструкции, ссылаясь на них, не зацикляясь на том, будут ли они работать по назначению (за исключением того, что вы не можете использовать it после его удаления).
9
ответ дан D Coetzee 19 August 2018 в 12:18
поделиться
  • 1
    Я могу думать о другом преимуществе на самом деле, если цикл вызывает код, который стирает эту запись, повторяющуюся или предыдущую (и цикл не знает об этом), она будет работать без какого-либо вреда. Единственным ограничением является то, что что-то стирает то, на что указывает next_it или преемники. Также можно протестировать полностью очищенный список / карту. – Larswad 21 November 2017 в 16:13

Короче: «Как удалить с карты во время ее итерации?»

  • С помощью старой карты impl: вы не можете
  • с новым отображением карты: почти как предложил @KerrekSB.

Из GCC map impl (примечание GXX_EXPERIMENTAL_CXX0X):

#ifdef __GXX_EXPERIMENTAL_CXX0X__
      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // DR 130. Associative erase should return an iterator.
      /**
       *  @brief Erases an element from a %map.
       *  @param  position  An iterator pointing to the element to be erased.
       *  @return An iterator pointing to the element immediately following
       *          @a position prior to the element being erased. If no such 
       *          element exists, end() is returned.
       *
       *  This function erases an element, pointed to by the given
       *  iterator, from a %map.  Note that this function only erases
       *  the element, and that if the element is itself a pointer,
       *  the pointed-to memory is not touched in any way.  Managing
       *  the pointer is the user's responsibility.
       */
      iterator
      erase(iterator __position)
      { return _M_t.erase(__position); }
#else
      /**
       *  @brief Erases an element from a %map.
       *  @param  position  An iterator pointing to the element to be erased.
       *
       *  This function erases an element, pointed to by the given
       *  iterator, from a %map.  Note that this function only erases
       *  the element, and that if the element is itself a pointer,
       *  the pointed-to memory is not touched in any way.  Managing
       *  the pointer is the user's responsibility.
       */
      void
      erase(iterator __position)
      { _M_t.erase(__position); }
#endif

Пример со старым и новым стилем:

#include <iostream>
#include <map>
#include <vector>
#include <algorithm>

using namespace std;
typedef map<int, int> t_myMap;
typedef vector<t_myMap::key_type>  t_myVec;

int main() {

    cout << "main() ENTRY" << endl;

    t_myMap mi;
    mi.insert(t_myMap::value_type(1,1));
    mi.insert(t_myMap::value_type(2,1));
    mi.insert(t_myMap::value_type(3,1));
    mi.insert(t_myMap::value_type(4,1));
    mi.insert(t_myMap::value_type(5,1));
    mi.insert(t_myMap::value_type(6,1));

    cout << "Init" << endl;
    for(t_myMap::const_iterator i = mi.begin(); i != mi.end(); i++)
        cout << '\t' << i->first << '-' << i->second << endl;

    t_myVec markedForDeath;

    for (t_myMap::const_iterator it = mi.begin(); it != mi.end() ; it++)
        if (it->first > 2 && it->first < 5)
            markedForDeath.push_back(it->first);

    for(size_t i = 0; i < markedForDeath.size(); i++)
        // old erase, returns void...
        mi.erase(markedForDeath[i]);

    cout << "after old style erase of 3 & 4.." << endl;
    for(t_myMap::const_iterator i = mi.begin(); i != mi.end(); i++)
        cout << '\t' << i->first << '-' << i->second << endl;

    for (auto it = mi.begin(); it != mi.end(); ) {
        if (it->first == 5)
            // new erase() that returns iter..
            it = mi.erase(it);
        else
            ++it;
    }

    cout << "after new style erase of 5" << endl;
    // new cend/cbegin and lambda..
    for_each(mi.cbegin(), mi.cend(), [](t_myMap::const_reference it){cout << '\t' << it.first << '-' << it.second << endl;});

    return 0;
}

печатает:

main() ENTRY
Init
        1-1
        2-1
        3-1
        4-1
        5-1
        6-1
after old style erase of 3 & 4..
        1-1
        2-1
        5-1
        6-1
after new style erase of 5
        1-1
        2-1
        6-1

Process returned 0 (0x0)   execution time : 0.021 s
Press any key to continue.
4
ответ дан Kashyap 19 August 2018 в 12:18
поделиться

Предполагая, что C ++ 11, это тело цикла с одним слоем, если это соответствует вашему стилю программирования:

using Map = std::map<K,V>;
Map map;

// Erase members that satisfy needs_removing(itr)
for (Map::const_iterator itr = map.cbegin() ; itr != map.cend() ; )
  itr = needs_removing(itr) ? map.erase(itr) : std::next(itr);

Пара других незначительных изменений стиля:

  • Показывать объявленный тип (Map::const_iterator), когда это возможно / удобно, используя auto.
  • Используйте using для типов шаблонов, чтобы сделать вспомогательные типы (Map::const_iterator) проще читать / поддерживать.
0
ответ дан Matt 19 August 2018 в 12:18
поделиться

Довольно грустно, а? Обычно я делаю это, создавая контейнер итераторов вместо удаления во время обхода. Затем прокрутите контейнер и используйте map.erase ()

std::map<K,V> map;
std::list< std::map<K,V>::iterator > iteratorList;

for(auto i : map ){
    if ( needs_removing(i)){
        iteratorList.push_back(i);
    }
}
for(auto i : iteratorList){
    map.erase(*i)
}
3
ответ дан Michael Daum 19 August 2018 в 12:18
поделиться