Попытка базового представления erlang couchdb - PullRequest
0 голосов
/ 10 июня 2018

Я пытаюсь сделать простое представление, когда оно генерирует только те документы, идентификатор которых начинается с «rating-».Кажется, я не могу вызывать какие-либо функции "string:" вообще в couchdb.На самом деле не знаю, как это сделать ... Каждый пример, который я видел, никогда не сравнивает часть значения, всегда полное значение.В ecmascript я бы, наверное, просто сделал if (!doc._id.indexOf('rating-')).В этом коде ниже он жалуется, что один из аргументов, предоставленных для split, неверен.

fun({Doc}) ->
    Id = proplists:get_value(<<"_id">>, Doc),
    DocChk = binary:split(Id, <<"-">>),
    case array:get(0, DocChk) of
      <<"rating-">> -> Emit(Id, nil)
    end
end.

У меня было несколько попыток, я пробовал что-то в оболочке Erlang, и хотя иногда я не могуполучить синтаксическую ошибку, я никогда не могу заставить что-либо работать на couchdb.Это весь взгляд, который я пытаюсь адаптировать из ecmascript.Как вы можете видеть ... я все еще застрял в строке 1 lol.

Карта

function (doc) {
  if (doc._id.indexOf('rating-') !== 0) return;
  if (!doc.isValid) return;
  var nps;
  doc.results.forEach(function (r) {
    if (r.type === 'Nps') {
      nps = r;
    }
  });

  if (!nps) return;
  var result = { t: 1, d: 0, p: 0 };

  switch (nps.score) {
    case 10:
    case 9:
      result.p++;
      break;
    case 8:
    case 7:
      break;
    default:
      result.d++;
      break;
  }

  var week = new Date(doc.dateCaptured.year, doc.dateCaptured.month -1, doc.dateCaptured.day);
  week.setDate(week.getDate() - ((week.getDay() === 0 ? 7 : week.getDay())-1));

  emit(['week', doc.companyId, week.getFullYear(), week.getMonth()+1, week.getDate()], result);
  emit(['day', doc.companyId, doc.dateCaptured.year, doc.dateCaptured.month, doc.dateCaptured.day], result);
  emit(['month', doc.companyId, doc.dateCaptured.year, doc.dateCaptured.month], result);
  emit(['year', doc.companyId, doc.dateCaptured.year], result);

  emit(['week-bylocation', doc.companyId, doc.locationId, week.getFullYear(), week.getMonth()+1, week.getDate()], result);
  emit(['day-bylocation', doc.companyId, doc.locationId, doc.dateCaptured.year, doc.dateCaptured.month, doc.dateCaptured.day], result);
  emit(['month-bylocation', doc.companyId, doc.locationId, doc.dateCaptured.year, doc.dateCaptured.month], result);
  emit(['year-bylocation', doc.companyId, doc.locationId, doc.dateCaptured.year], result);

  emit(['week-bysource', doc.companyId, doc.sourceId, week.getFullYear(), week.getMonth()+1, week.getDate()], result);
  emit(['day-bysource', doc.companyId, doc.sourceId, doc.dateCaptured.year, doc.dateCaptured.month, doc.dateCaptured.day], result);
  emit(['month-bysource', doc.companyId, doc.sourceId, doc.dateCaptured.year, doc.dateCaptured.month], result);
  emit(['year-bysource', doc.companyId, doc.sourceId, doc.dateCaptured.year], result);
}

Уменьшить

function (keys, values, rereduce) {
  var result = { t: 0, p: 0, d: 0 };
  values.forEach(function (v) {
    result.t += v.t;
    result.p += v.p;
    result.d += v.d;
  });

  return result;
}

Производительность этого представления простослишком медленно.Это не будет проблемой постепенно, но мне нужно заполнить строки индекса 6,3 млн., И это займет около 12 часов на кластере из 3 узлов с общим количеством ядер 12.Определенно процессор.

Редактировать

Благодаря Hynek я смог перенести свою функцию карты.Я уверен, что это очень неэффективный эрланг, но он, кажется, примерно в 30 раз быстрее, чем его аналог ecmascript.

fun({Doc}) ->
    case lists:keyfind(<<"_id">>, 1, Doc) of
        {_, <<"rating-", _/bytes>> = Id} -> 
          case couch_util:get_value(<<"isValid">>, Doc) of
            true -> 
              Results = proplists:get_value(<<"results">>, Doc),

              case lists:dropwhile(fun({R}) -> <<"Nps">> /= proplists:get_value(<<"type">>, R) end, Results) of
                [] -> ok;
                [{Nps} | _] -> 
                  Score = proplists:get_value(<<"score">>, Nps),
                  A = case Score of 
                    S when S > 8 -> [1, 0, 1];
                    S when S > 6 -> [0, 0, 1];
                    _ -> [0, 1, 1]
                  end,
                  CompanyId = proplists:get_value(<<"companyId">>, Doc),
                  LocationId = proplists:get_value(<<"locationId">>, Doc),
                  SourceId = proplists:get_value(<<"sourceId">>, Doc),
                  {DateCaptured} = proplists:get_value(<<"dateCaptured">>, Doc),
                  Year = proplists:get_value(<<"year">>, DateCaptured),
                  Month = proplists:get_value(<<"month">>, DateCaptured),
                  Day = proplists:get_value(<<"day">>, DateCaptured),
                  Emit([<<"year">>, CompanyId, Year], A),
                  Emit([<<"month">>, CompanyId, Year, Month], A),
                  Emit([<<"day">>, CompanyId, Year, Month, Day], A),

                  Emit([<<"year-bylocation">>, CompanyId, LocationId, Year], A),
                  Emit([<<"month-bylocation">>, CompanyId, LocationId, Year, Month], A),
                  Emit([<<"day-bylocation">>, CompanyId, LocationId, Year, Month, Day], A),

                  Emit([<<"year-bysource">>, CompanyId, SourceId, Year], A),
                  Emit([<<"month-bysource">>, CompanyId, SourceId, Year, Month], A),
                  Emit([<<"day-bysource">>, CompanyId, SourceId, Year, Month, Day], A)

              end;
            _ -> ok
          end;
        _ -> ok
    end
end.

1 Ответ

0 голосов
/ 10 июня 2018

Проблема в том, что binary:split/2 результат не является array, поэтому вы не можете использовать array:get/2.Ну, любой опытный Эрлангер написал бы это так:

fun({Doc}) ->
    case lists:keyfind(<<"_id">>, 1, Doc) of
        {_, <<"rating-", _/bytes>> = Id} -> Emit(Id, nil);
        _ -> ok
    end
end.

Или, если вы чувствуете себя менее предприимчивым и хотели бы придерживаться рекомендуемых функций (возможно, немного медленнее):

fun({Doc}) ->
    case couch_util:get_value(<<"_id">>, Doc) of
        <<"rating-", _/bytes>> = Id -> Emit(Id, nil);
        _ -> ok
    end
end.

Редактировать : Значение = в Эрланге нуждается в дополнительных пояснениях.Знак равенства в Эрланге больше похож на равенство в математике, но не совсем.

1> X = 1.
1
2> 1 = X.
1
3> 1 = A = X.
1
4> A.
1
5> B = 1 = X.
1
6> B.
1
7> 1 = Z.
* 1: variable 'Z' is unbound
8> 2 = X.
** exception error: no match of right hand side value 1

Что там происходит?Знак = имеет два разных значения и работает в тесном контакте с одним назначением или связыванием.Во-первых, это оператор совпадения в выражении.Вместо любого выражения вы можете написать выражение соответствия:

 <Pattern> = <Expression>

Это самое правое = в 3-м и 5-м выражении и единственное = в других выражениях в приведенном выше примере.После 1-го выражения X уже является связанной переменной со значением 1 и слева от нее находится шаблон.Шаблон может быть простым значением или переменным или составным шаблоном.Переменная может быть связана или не связана.Если переменная не связана, она привязывается к значению.Если переменная уже связана, проверяется соответствие.При использовании в выражении сопоставления ошибка сопоставления вызывает исключение badmatch (класс error), которое отображается в удобочитаемом формате в оболочке, как для восьмого выражения, поскольку я не знаю R17-иш.В любом случае, вы не можете изменить левую и правую части оператора = в выражении соответствия, потому что привязка переменной может происходить только в шаблоне, например, левый операнд =, как показано в 7-м выражении.

Но вытакже можно использовать = в паттерне, и там это работает как объединение, которое намного больше похоже на равенство в математике, и там вы можете свободно переключаться влево и вправо.Опытные эрлангеры используются для написания шаблонов так, как я использовал в своем примере по простой причине.Если вы читаете шаблон, вы хотели бы знать, как значение должно выглядеть как первое и переменное, где вы хотели бы связать значение как второе, как менее важное или что-то, что вам нужно знать позже в процессе чтения кода.

Шаблоны появляются не только в выражениях совпадений, но и в выражениях функций (на самом деле {Doc} в этом примере также является шаблоном), а также в выражениях case, try, receive и в списках.генераторы.Сопоставление с образцом - это одна из самых мощных и интересных возможностей самого языка Эрланга, и в моем примере я лишь продемонстрирую это.Вы можете деконструировать сложные структуры данных в виде кортежей, таких как {_, <<"rating-", _/bytes>> = Id}.Вы можете сопоставлять двоичные файлы с образцом, как показано в этой части <<"rating-", _/bytes>>.

Для сопоставления с образцом двоичных файлов используется Синтаксис битов , который является мощным инструментом, который делает реализацию двоичных протоколов в Erlang простой и увлекательной, но здесь яиспользуйте его, чтобы сделать код намного более эффективным и понятным, чем аналог ecmascript.Здесь я просто четко заявляю, что меня интересует двоичный файл, который начинается с префикса rating- и продолжается что угодно (любые бинарные бинарные данные) _/bytes.(Я предпочитаю использовать bytes и bits вместо binary и bitstring, потому что это кажется более выраженным намерением.)

...