Как рассчитать список «веб-страниц» с наиболее уникальными представлениями «страницы» в массиве хэшей? - PullRequest
0 голосов
/ 20 июня 2019

У меня есть текстовый файл, в котором указано, сколько раз конкретная страница была посещена IP-адресом, например:

/help_page/1 126.318.035.038
/contact 184.123.665.067
/home 184.123.665.067
/about/2 444.701.448.104
/help_page/1 929.398.951.889
/index 444.701.448.104
/help_page/1 722.247.931.582
/about 061.945.150.735
/help_page/1 646.865.545.408
/home 235.313.352.950

Теперь мне нужно распечатать список, проанализировав файл журнала с большинством просмотров страниц, упорядоченных от большинства просмотров страниц к меньшему количеству просмотров страниц, и мне удалось получить правильный результат.

Вторая задача - распечатать список веб-страниц, показывающих уникальные просмотры страниц, и здесь у меня возникло несколько проблем.

Вот код, который печатает общее количество просмотров страниц, упорядоченных от высокого к низкому:

require 'open-uri'

log_read = File.read('webserver.log')

split_log = log_read.split("\n/") # split_log = array

split_log[0] = split_log[0].sub('/', '')

split_array = split_log.map { |line| line.split(' ') }

# Most views
container = Hash.new(0) # empty

split_array.each do |item|
  container[item[0]] += 1
end

sorted_container = container.sort_by { |_k, v| v }.reverse

# Number of page visits
sorted_container.each do |k, v|
  puts "#{k} has #{v} visits"
end

the result of the above code is : 
about/2 has 90 visits
contact has 89 visits
index has 82 visits
about has 81 visits
help_page/1 has 80 visits
home has 78 visits

Теперь для второй части, где меня просят показать список веб-страниц с уникальным просмотром страниц, я подумал отобразить «split_array» следующим образом:

sorted_unique_views = split_array.map { |h| h.to_a }.uniq.map { |k, v| { k => v } }

which will give me an array of hashes : 
[
{"help_page/1"=>"126.318.035.038"}
{"contact"=>"184.123.665.067"}
{"home"=>"184.123.665.067"}
{"about/2"=>"444.701.448.104"}
{"help_page/1"=>"929.398.951.889"}
{"index"=>"444.701.448.104"}
{"help_page/1"=>"722.247.931.582"}
{"about"=>"061.945.150.735"}
{"help_page/1"=>"646.865.545.408"}
{"home"=>"235.313.352.950"}
{"help_page/1"=>"543.910.244.929"}
....etc ]

То, что я на самом деле хочу, это как-то перебрать sorted_unique_views = [{...}, {...} и т. Д.] И суммировать уникального IP-корреспондента для каждой страницы, конечный результат будет выглядеть примерно так:

help_page/1 23
contact 23
home 22
about/2 22
index 23
about 22

Я пробовал ввести, перебирая sorted_unique_views = [{...}, {...} и т. Д.], Но я получаю либо: 135, что является суммой всех уникальных просмотров страниц, либо я получаю

{{"help_page/1"=>"126.318.035.038"}=>1} 

Я хотел бы получить некоторые рекомендации и отзывы, если это возможно, а также, если выбор расщепления и последующего отображения является правильным в моем случае.

Большое спасибо

1 Ответ

0 голосов
/ 20 июня 2019

Создать тестовый файл

Давайте сначала создадим файл 1 .

text =<<-END
/help_page/1 126.318.035.038
/contact 184.123.665.067
/home 184.123.665.067
/about/2 444.701.448.104
/help_page/1 929.398.951.889
/index 444.701.448.104
/help_page/1 722.247.931.582
/about 061.945.150.735
/help_page/1 646.865.545.408
/home 235.313.352.950
END

FNAME = 'log'
File.write(FNAME, text)
  #=> 256

Подтвердите его содержание.

puts File.read(FNAME)
/help_page/1 126.318.035.038
/contact 184.123.665.067
/home 184.123.665.067
...
/home 235.313.352.950

Прочитайте файл и создайте полезный хеш

h = File.foreach(FNAME).with_object(Hash.new { |h,k| h[k] = [] }) do |line,h|
  key, url = line[1..-2].split
  h[key] << url
end
  #=> {"help_page/1"=>["126.318.035.038", "929.398.951.889", "722.247.931.582",
  #                    "646.865.545.408"],
  #    "contact"    =>["184.123.665.067"],
  #    "home"       =>["184.123.665.067", "235.313.352.950"],
  #    "about/2"    =>["444.701.448.104"],
  #    "index"      =>["444.701.448.104"],
  #    "about"      =>["061.945.150.735"]} 

Используйте этот хэш для вычисления объектов, представляющих интерес

Определение количества просмотров для каждой клавиши

h.transform_values(&:count)
  #=> {"help_page/1"=>4, "contact"=>1, "home"=>2, "about/2"=>1, "index"=>1, "about"=>1} 

Создать список убывающих просмотров страниц

h.sort_by { |_,a| -a.size }
  #=> [["help_page/1", ["126.318.035.038", "929.398.951.889", "722.247.931.582",
  #                     "646.865.545.408"]],
  #    ["home",    ["184.123.665.067", "235.313.352.950"]],
  #    ["contact", ["184.123.665.067"]],
  #    ["about/2", ["444.701.448.104"]],
  #    ["index",   ["444.701.448.104"]],
  #    ["about",   ["061.945.150.735"]]] 

или, в зависимости от требований:

h.sort_by { |_,a| -a.size }.to_h
  #=> {"help_page/1"=>["126.318.035.038", "929.398.951.889", "722.247.931.582",
  #                    "646.865.545.408"],
  #    "home"       =>["184.123.665.067", "235.313.352.950"],
  #    "contact"    =>["184.123.665.067"],
  #    "about/2"    =>["444.701.448.104"],
  #    "index"      =>["444.701.448.104"],
  #    "about"      =>["061.945.150.735"]} 

Определите, какие ключи были просмотрены только один раз

h.select { |_,a| a.size == 1 }
  #=> {"contact"=>["184.123.665.067"],
  #    "about/2"=>["444.701.448.104"],
  #    "index"=>["444.701.448.104"],
  #    "about"=>["061.945.150.735"]}

Объяснение

См. IO :: write , IO :: read , IO :: foreach , Перечислитель # with_object , Hash :: new , Hash # transform_values ​​, Enumerable # count и Enumerable # sort_by . 2

Вычисление h альтернативно может быть записано следующим образом.

h = {}
File.foreach(FNAME) do |line|
  key, url = line[1..-2].split
  h[key] = [] unless h.key?(key)
  h[key] << url
end
h

Это объясняет .each_object и Hash.new { |h,k| h[k] = [] }. line[1..-2] обрезает первый символ строки (/) и символ новой строки ("\n) в конце строки.

h.transform_values(&:count)

является сокращением для:

h.transform_values { |v| v.count }

1. Для удобства форматирования я выделил каждую строку heredoc ниже 4 пробелов. Для запуска кода сначала удалите отступ строки heredoc.

2. Методы класса и модуля обозначаются двойной двоеточием между классом или модулем и именем метода (например, IO::write); методы экземпляра обозначаются знаком решетки между классом или модулем и методом экземпляра (например, Enumerator#each_object). Методы IO часто вызываются в классе File (например, File.foreach ... вместо IO.foreach ...). Это допустимо, потому что File является подклассом IO и поэтому наследует IO методы класса и экземпляра.

...