<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7460359136037979439</id><updated>2012-01-20T15:07:04.809+04:00</updated><category term='поисковые системы'/><category term='java'/><category term='c++'/><category term='интернет-математика'/><category term='разработка'/><category term='компьютерное зрение'/><category term='алгоритмы'/><title type='text'>No birds</title><subtitle type='html'>Хаос всегда победит систему потому, что он лучше организован</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://ornitos.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://ornitos.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Орнитос</name><uri>http://www.blogger.com/profile/12064108298006689502</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://bp2.blogger.com/_k7xapXUhZ_s/SJPXQ06KswI/AAAAAAAAAAM/2K6WJemR5iE/s1600-R/000c9pyk'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>15</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7460359136037979439.post-7111088702362835119</id><published>2009-03-16T15:38:00.011+03:00</published><updated>2009-03-16T16:55:24.767+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='интернет-математика'/><category scheme='http://www.blogger.com/atom/ns#' term='поисковые системы'/><title type='text'>PageRank и блочная структура web</title><content type='html'>Каждая страница в web может однозначно идентифицироваться парой чисел: идентификатором сайта, на котором она находится, и внутрисайтовым идентификатором страницы (уникальным только в пределах сайта). Эту пару можно считать уникальным идентификатором страницы в web.&lt;br /&gt;&lt;br /&gt;Нарисуем график. По осям x и y расположим web-страницы, упорядоченные по их идентификатору: порядок определяется идентификатором сайта, а для страниц одного сайта – внутрисайтовым идентификатором. Если страница a ссылается на страницу b, на графике нарисуем точку с координатой (a, b). Вот так выглядит такой график:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align:center"&gt;&lt;img src="http://3.bp.blogspot.com/_k7xapXUhZ_s/Sb5I0U7BQII/AAAAAAAAADA/C7Oda_79SFA/s1600/1.png"/&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Если ограничиться только страницами из домена .com, то график выглядит так:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align:center"&gt;&lt;img src="http://2.bp.blogspot.com/_k7xapXUhZ_s/Sb5I5DexSmI/AAAAAAAAADI/gl-nde-md58/s1600/2.png"/&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Приблизимся ещё на один шаг – рассмотрим страницы, принадлежащие сайтам доменов stanford.edu и berkeley.edu:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align:center"&gt;&lt;img src="http://2.bp.blogspot.com/_k7xapXUhZ_s/Sb5I8me7bPI/AAAAAAAAADQ/0QWVvrseNa4/s1600/3.png"/&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Картинки взяты из Efficient Parallel Computation of PageRank (Christian Kohlschutter и др.) и Exploiting the Block Structure of theWeb for Computing PageRank (Sepandar D. Kamvar и др.).&lt;br /&gt;&lt;br /&gt;Диагонали на графиках состоят из цепочки квадратных блоков. Некоторые из них больше, некоторые меньше, но в основном они имеют примерно одинаковый размер. &lt;br /&gt;&lt;br /&gt;Каждый такой блок – это отдельный сайт. Страницы внутри сайта связаны ссылками между собой гораздо плотнее, чем со страницами других сайтов. По статистике 90% ссылок в web – внутрисайтовые. &lt;br /&gt;&lt;br /&gt;Это открытие способствовало появлению алгоритмов вычисления PageRank, которые позволяют, как ускорить само вычисление, так и осуществлять его параллельно на нескольких машинах.&lt;br /&gt;&lt;br /&gt;Самый известный из них так и называется – метод блочной структуры.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Метод блочной структуры (Block structure method)&lt;/h3&gt;&lt;br /&gt;Алгоритм состоит из четырёх шагов:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1.&lt;/b&gt; Строится граф сайтов. В этом графе сайт a связан с сайтом b, если на сайте a есть страница, ссылающаяся на страницу сайта b. Для этого графа выполняется классический PageRank. В результате для каждого сайта мы имеем некое число, которое можно назвать его рейтингом. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;2.&lt;/b&gt; Затем каждый сайт обрабатывается в отдельности. Мы анализируем внутреннюю структуру: применяем классический PageRank к графу страниц сайта. Ссылки между сайтами игнорируются. Таким образом, для каждой страницы мы получаем так называемый локальный PageRank. Этот этап можно выполнять параллельно на нескольких машинах.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3.&lt;/b&gt; Локальный PageRank каждой страницы умножается на рейтинг сайта, на котором она находится и записывается в вектор Z.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;4.&lt;/b&gt; Вектор Z используется как начальный вектор для вычисления классического PageRank для полного графа web-страниц. При использовании такого начального вектора, необходимое количество итераций сокращается вплоть до 50%.&lt;br /&gt;&lt;br /&gt;Вычисление локального PageRank имеет следующие свойства:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1.&lt;/b&gt; Т.к. отдельные сайты значительно меньше всего web, локальный PageRank можно вычислять, храня необходимые данные в памяти, а не на жёстком диске, что существенно ускорит работу&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2.&lt;/b&gt; Локальный PageRank можно вычислять параллельно на нескольких машинах&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3.&lt;/b&gt; Алгоритм PageRank для графа страниц большинства сайтов сходится достаточно быстро&amp;nbsp;– иногда бывает достаточно всего нескольких итераций&lt;br /&gt;&lt;br /&gt;То есть выигрыш метода блочной структуры достигается за счёт того, что 50% итераций PageRank на полном графе заменяются более эффективными операциями.&lt;br /&gt;&lt;br /&gt;Сайт, как правило, считается синонимом хост. Конечно, есть методы определения более точных границ сайта на основе алгоритмов кластеризации. Но, я полагаю, что приближение сайт = хост работает вполне адекватно.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Метод блочной структуры – это только один из алгоритмов, вдохновлённых блочной структурой web. Другие алгоритмы отличаются в основном 3-м и 4-м этапом – т.е. тем как из рейтинга сайтов и локальных PageRank получается окончательный результат. &lt;br /&gt;&lt;br /&gt;Многие из этих алгоритмов добиваются существенного ускорения работы за счёт отказа от вычисления точного PageRank и вычисляют его аппроксимацию. Аппроксимации часто бывает вполне достаточно. Это позволяет отказаться от вычислительно самого сложного 4-го этапа – вычисления PageRank для полного графа web-страниц. Подробную информацию можно найти среди статей из &lt;a href="http://ornitos.blogspot.com/2009/03/pagerank_16.html"&gt;подборки&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Siterank&lt;/h3&gt;&lt;br /&gt;PageRank страницы не зависит от того, на каком сайте она находится. Роль играют только связи между страницами. &lt;br /&gt;&lt;br /&gt;В экспериментальной области исследований находятся алгоритмы, использующие рейтинг сайта (аналогичный полученному на первом этапе метода блочной структуры) не для аппроксимации PageRank, а для получения более качественного ранжирования.&lt;br /&gt;&lt;br /&gt;Недостатком PageRank является то, что он поощряет старые страницы, на которые уже накопилось много ссылок, и недооценивает новые, на которые ссылки ещё не успели появиться в большом количестве. &lt;br /&gt;&lt;br /&gt;Если учитывать рейтинг сайта, у новой страницы, появившейся на хорошем сайте, уже сразу может быть некий стартовый бонус, что не позволит ей потеряться в пучине. &lt;br /&gt;&lt;br /&gt;Такой алгоритм, учитывающий структуру межсайтовых связей, может быть более устойчивым к поисковому спаму – манипулировать структурой страниц гораздо проще, чем структурой связей между сайтами (хостами).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7460359136037979439-7111088702362835119?l=ornitos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ornitos.blogspot.com/feeds/7111088702362835119/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7460359136037979439&amp;postID=7111088702362835119' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/7111088702362835119'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/7111088702362835119'/><link rel='alternate' type='text/html' href='http://ornitos.blogspot.com/2009/03/web.html' title='PageRank и блочная структура web'/><author><name>Орнитос</name><uri>http://www.blogger.com/profile/12064108298006689502</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://bp2.blogger.com/_k7xapXUhZ_s/SJPXQ06KswI/AAAAAAAAAAM/2K6WJemR5iE/s1600-R/000c9pyk'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_k7xapXUhZ_s/Sb5I0U7BQII/AAAAAAAAADA/C7Oda_79SFA/s72-c/1.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7460359136037979439.post-3518861935190723525</id><published>2009-03-16T15:30:00.004+03:00</published><updated>2011-09-06T14:36:01.386+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='интернет-математика'/><category scheme='http://www.blogger.com/atom/ns#' term='поисковые системы'/><title type='text'>Подборка статей о PageRank</title><content type='html'>Вот выложил небольшую подборку статей о PageRank: &lt;a href="http://narod.ru/disk/24215447001/PR.zip.html"&gt;скачать&lt;/a&gt; [14.3 МБ]. В них можно найти более подробную информацию о всём том, что я рассказывал о PageRank, и не только. Статьи на английском.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7460359136037979439-3518861935190723525?l=ornitos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ornitos.blogspot.com/feeds/3518861935190723525/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7460359136037979439&amp;postID=3518861935190723525' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/3518861935190723525'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/3518861935190723525'/><link rel='alternate' type='text/html' href='http://ornitos.blogspot.com/2009/03/pagerank_16.html' title='Подборка статей о PageRank'/><author><name>Орнитос</name><uri>http://www.blogger.com/profile/12064108298006689502</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://bp2.blogger.com/_k7xapXUhZ_s/SJPXQ06KswI/AAAAAAAAAAM/2K6WJemR5iE/s1600-R/000c9pyk'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7460359136037979439.post-2923120312309016038</id><published>2009-03-12T17:50:00.062+03:00</published><updated>2009-03-16T16:14:29.050+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='интернет-математика'/><category scheme='http://www.blogger.com/atom/ns#' term='поисковые системы'/><title type='text'>Развитие PageRank</title><content type='html'>С того момента, когда PageRank был впервые представлен в 1998 году, было потрачено немало усилий, чтобы улучшить его качество и скорость вычисления. В этой обзорной и достаточно популярной статье я опишу основные направления исследований вокруг PageRank и варианты алгоритма.&lt;br /&gt;&lt;br /&gt;Я разрабатываю систему оценки важности web-страниц на основе входящих и исходящих ссылок в компании &lt;a href="http://nigma.ru/"&gt;Нигма&lt;/a&gt;, поэтому смотрю на PageRank с математической стороны, со стороны разработчика а не seo.&lt;br /&gt;&lt;br /&gt;Я не буду пересказывать здесь многократно описанные основы PageRank. Предполагается, что читатель знает, что это вообще такое. Если же нет, то для начала могу порекомендовать статью &lt;a href="http://digits.ru/articles/promotion/pagerank.html"&gt;Растолкованный PageRank&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;На следующей картинке схематически представлены основные направления исследований, окруживших PageRank. Каждому овалу на схеме будет соответствовать отдельная глава статьи.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://4.bp.blogspot.com/_k7xapXUhZ_s/SblC93qpCbI/AAAAAAAAABg/oBztago6Fkg/s1600/Screenshot.ru.png" /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;PageRank с математической стороны&lt;/h3&gt;&lt;br /&gt;PageRank основан на математической модели случайного блуждания «пользователя» в сети интернет. В некоторый момент он находится на одной странице, затем случайным образом выбирает одну из ссылок и переходит по ней на другую. «Пользователь» произвольно выбирает ссылки, не отдавая предпочтение каким-либо из них.&lt;br /&gt;&lt;br /&gt;PageRank страницы – это вероятность того, что блуждающий «пользователь» находится на данной странице.&lt;br /&gt;&lt;br /&gt;Сделаем небольшой набросок того, как рассчитать эту вероятность.&lt;br /&gt;&lt;br /&gt;Пронумеруем web-страницы целыми числами от 1 до N.&lt;br /&gt;&lt;br /&gt;Сформируем матрицу переходов P, содержащую вероятность перехода «пользователя» с одной страницы на другую. Пусть deg(i) – количество исходящих ссылок на странице i. В таком случае, вероятность перехода со страницы i на страницу j равна:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;P[i, j] = 1 / deg(i), если i ссылается на j&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;P[i, j] = 0, если i не ссылается на j&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Пусть p&lt;sup&gt;(k)&lt;/sup&gt; – это вектор, содержащий для каждой страницы вероятность того, что в момент k на ней находится «пользователь». Этот вектор – распределение вероятностей местоположения «пользователя».&lt;br /&gt;&lt;br /&gt;Предположим, что «пользователь» может начать своё бесцельное блуждание с любой страницы. То есть, начальное распределение вероятностей &lt;a href="http://ru.wikipedia.org/wiki/%D0%94%D0%B8%D1%81%D0%BA%D1%80%D0%B5%D1%82%D0%BD%D0%BE%D0%B5_%D1%80%D0%B0%D0%B2%D0%BD%D0%BE%D0%BC%D0%B5%D1%80%D0%BD%D0%BE%D0%B5_%D1%80%D0%B0%D1%81%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5"&gt;равномерно&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Зная распределение вероятностей в момент k, мы можем узнать распределение вероятностей в момент k+1 по следующей формуле:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://4.bp.blogspot.com/_k7xapXUhZ_s/SblGUaOb9BI/AAAAAAAAABw/X4fN2xX9sDY/s1600/pr1.png" /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;В основе этой формулы не более чем правила сложения и умножения вероятностей.&lt;br /&gt;&lt;br /&gt;Математически мы пришли к &lt;a href="http://ru.wikipedia.org/wiki/%D0%A6%D0%B5%D0%BF%D1%8C_%D0%9C%D0%B0%D1%80%D0%BA%D0%BE%D0%B2%D0%B0"&gt;цепи Маркова&lt;/a&gt; с матрицей переходов P, где каждая web-страница представляет собой одно из состояний цепи.&lt;br /&gt;&lt;br /&gt;Но нам нужно знать вероятность нахождения «пользователя» на странице независимо от того, сколько шагов k он сделал от точки начала блуждания.&lt;br /&gt;&lt;br /&gt;Мы берём начальное распределение вероятностей p&lt;sup&gt;(0)&lt;/sup&gt;. Считаем по представленной выше формуле распределение p&lt;sup&gt;(1)&lt;/sup&gt;. Затем по той же формуле считаем p&lt;sup&gt;(2)&lt;/sup&gt;, затем p&lt;sup&gt;(3)&lt;/sup&gt; и т.д. до тех пор, пока некие p&lt;sup&gt;(k-1)&lt;/sup&gt; и p&lt;sup&gt;(k)&lt;/sup&gt; не будут отличаться лишь незначительно  (полное равенство будет достигнуто при k стремящемся к бесконечности).&lt;br /&gt;&lt;br /&gt;Таким образом, последовательность p&lt;sup&gt;(1)&lt;/sup&gt;, p&lt;sup&gt;(2)&lt;/sup&gt;, p&lt;sup&gt;(3)&lt;/sup&gt; … сойдётся к некому вектору p = p&lt;sup&gt;(k)&lt;/sup&gt;. Интересно, что вектор p на самом деле не зависит от начального распределения (т.е. от того, с какой страницы начал своё блуждание воображаемый «пользователь»).&lt;br /&gt;&lt;br /&gt;Вектор p таков, что в любой момент (начиная с некоторого момента k), вероятность того, что «пользователь» находится на странице i, равна p[i]. Это и есть искомый PageRank.&lt;br /&gt;&lt;br /&gt;Этот алгоритм называется методом степеней (&lt;a href="http://en.wikipedia.org/wiki/Power_method"&gt;power method&lt;/a&gt;). Он сойдётся только в том случае, если выполняются два условия: граф страниц должен быть сильно связным и апериодическим. Как достигается выполнение первого условия, будет рассмотрено далее. Второе же без дополнительных усилий справедливо для структуры web.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Примечание&lt;/h4&gt;&lt;br /&gt;При выполнении условий сильной связности и апериодичности, согласно эргодической теореме, цепь Маркова с матрицей перехода P имеет единственное стационарное распределение p:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://3.bp.blogspot.com/_k7xapXUhZ_s/SbqTErJYJjI/AAAAAAAAACQ/3fIwwj6x_ec/s1600/pr2.png" /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;PageRank и является стационарным распределением цепи Маркова.&lt;br /&gt;&lt;br /&gt;Также это выражение представляет собой собственную систему, а вектор p — собственный вектор матрицы A. Поэтому и применяется метод степеней — численный метод для поиска собственных векторов.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Висячие узлы (dangling nodes)&lt;/h3&gt;&lt;br /&gt;Висячие узлы – это страницы, которые не имеют исходящих ссылок. Страница может не иметь исходящих ссылок просто потому, что у неё их нет, либо потому, что она не была прокраулена (crawled) – т.е. страница попала в базу, т.к. на неё ссылаются другие прокрауленные страницы, но сама прокраулена не была, и о её исходящих ссылках ничего не известно.&lt;br /&gt;&lt;br /&gt;Для вычисления PageRank в графе страниц не должно быть висячих узлов. Сумма каждого ряда матрицы переходов должна быть равна единице (row-stochastic), для висячих же узлов она окажется равной 0 –  входные данные алгоритма будут некорректными.&lt;br /&gt;&lt;br /&gt;По статистике, даже если поисковая система имеет достаточно большой индекс, 60% страниц оказывается висячими. Поэтому то, как с ними поступать, оказывает большое влияние на ранжирование.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Метод удаления&lt;/h4&gt;&lt;br /&gt;Изначальный подход, предложенный Пэйджем, заключается в том, чтобы удалить висячие узлы перед вычислением PageRank. В качестве обоснования предлагается то, что висячие узлы не оказывают влияния на другие страницы. Но это не совсем так –  удаляя их, мы уменьшаем количество исходящих ссылок страниц, которые на них ссылаются. Тем самым мы увеличиваем значение PageRank, которое эти страницы передают через свои ссылки.&lt;br /&gt;&lt;br /&gt;Кроме того, удаление висячих узлов, может создать новые висячие узлы. Таким образом, требуется проделать несколько итераций удаления (обычно 5 или что-то около того).&lt;br /&gt;&lt;br /&gt;В качестве развития этого подхода, было предложено после вычисления PageRank возвращать удалённые узлы назад в граф и проделывать ещё столько же итераций алгоритма PageRank, сколько было проделано итераций удаления. Это позволяет получить значение PageRank и для висячих узлов.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Считать связанными со всеми другими страницами&lt;/h4&gt;&lt;br /&gt;Наиболее популярный трюк заключается в том, чтобы считать висячие узлы связанными со всеми другими страницами. В модели случайного блуждания данный метод находит подходящее объяснение: попав на страницу без исходящих ссылок, «пользователь» перескакивает на любую другую страницу сети случайным образом.&lt;br /&gt;&lt;br /&gt;Можно считать вероятность попадания «пользователя» на страницу из висячего узла в результате такого перескока распределённой равномерно среди всех страниц сети. Но можно и не считать её таковой. Например, можно исключить попадание из висячего узла на другой висячий узел. Или распределить вероятность между страницами по аналогии с аристократическим вектором телепортации, о котором будет рассказано ниже в главе Телепортация.&lt;br /&gt;&lt;br /&gt;Матрица переходов модифицируется следующим образом:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://3.bp.blogspot.com/_k7xapXUhZ_s/SbqUf7ertWI/AAAAAAAAACY/TFozGD8OItg/s1600/pr3.png" /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;d[i] = 1, если i – висячий узел, и 0 в противном случае&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;v[j] – вероятность попадания «пользователя» на страницу j из висячего узла&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Шаг назад (step back)&lt;/h4&gt;&lt;br /&gt;Проблему висячих узлов можно решить, добавив каждому такому узлу обратные ссылки на страницы, которые на него ссылаются. В модели блуждания это соответствует нажатию кнопки назад в браузере «пользователем», попавшим на страницу без исходящих ссылок. Этот метод критикуют за то, что он поощряет страницы с большим количеством ссылок на висячие узлы. Однако в некоторых моих экспериментах такой подход давал лучшее ранжирование.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Петля (self-link)&lt;/h4&gt;&lt;br /&gt;Упомяну кратко ещё один способ. Каждому висячему узлу можно добавить ссылку на самого себя – это приведёт в порядок матрицу переходов. Но после вычисления PageRank, результат придётся определённым образом скорректировать. Подробности описаны в G. Jeh and J.Widom “Scaling Personalized Web Search.”&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Телепортация&lt;/h3&gt;&lt;br /&gt;Решение проблемы висячих узлов ещё не даёт сильную связность графа. Поэтому вводится телепортация.&lt;br /&gt;&lt;br /&gt;В модели случайного блуждания это выглядит так: «пользователь», находясь на некоторой странице, с вероятностью &lt;span style="font-style: italic;"&gt;c&lt;/span&gt; переходит по одной из её ссылок и с вероятностью (1 – &lt;span style="font-style: italic;"&gt;c&lt;/span&gt;) * v[j] перескакивает (телепортируется) на страницу j. Стохастический вектор v описывает вероятность телепортации на ту или иную страницу и называется вектором телепортации. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;c&lt;/span&gt; как правило выбирается в диапазоне 0.85 – 0.9. Большие значения дают более точные результаты, но более медленную сходимость. Меньшие значения – быструю сходимость, но менее точные результаты.&lt;br /&gt;&lt;br /&gt;Плюс ко всему, чем меньше значение &lt;span style="font-style: italic;"&gt;с&lt;/span&gt;, тем больше возможностей для поискового спама – достаточно создать на сайте огромное количество страниц и они будут, как зонтик, собирать значительный PageRank, получаемый за счёт телепортации.&lt;br /&gt;&lt;br /&gt;Существует два способа выбора вектора телепортации: демократический и аристократический. Демократический вектор содержит одинаковые значения вероятности для всех страниц. Это стандартный вариант. Аристократический содержит низкую вероятность для обычных страниц и более высокую для избранных достоверно качественных неспамерских страниц. Последний способ явно поощряет избранные страницы в ущерб остальным, зато более устойчив к поисковому спаму.&lt;br /&gt;&lt;br /&gt;В одной из статей предлагалось делать более высокую вероятность телепортации для главных страниц сайтов, но мне не известно, каковы были результаты.&lt;br /&gt;&lt;br /&gt;Значение v[j] не должно быть равно 0. Иначе может оказаться, что j недосягаема из некой другой страницы, что означает нарушение сильной связности.&lt;br /&gt;&lt;br /&gt;Телепортация модифицирует матрицу переходов следующим образом:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://1.bp.blogspot.com/_k7xapXUhZ_s/SbqVJsOCYkI/AAAAAAAAACg/6o74Lw-EZpc/s1600/pr4.png" /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;v – вектор телепортации&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Мы ещё вернёмся к вектору телепортации, когда будем обсуждать персонализацию PageRank.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Ускорение метода степеней&lt;/h3&gt;&lt;br /&gt;Многие исследователи пытались ускорить сходимость метода степеней. Посмотрим на самые удачные способы.&lt;br /&gt;&lt;br /&gt;Для удобства повторю формулу, которую мы используем на каждой итерации. Назовём её формулой А:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://4.bp.blogspot.com/_k7xapXUhZ_s/SblGUaOb9BI/AAAAAAAAABw/X4fN2xX9sDY/s1600/pr1.png" /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Метод Гаусса-Зейделя (Gauss-Seidel method)&lt;/h4&gt;&lt;br /&gt;На каждой итерации в методе степеней мы используем значения элементов вектора p&lt;sup&gt;(k)&lt;/sup&gt; чтобы рассчитать вектор p&lt;sup&gt;(k+1)&lt;/sup&gt;. Отличие метода Гаусса-Зейделя в том, что мы сразу используем значения вычисленных элементов вектора p&lt;sup&gt;(k+1)&lt;/sup&gt; для вычисления его остальных элементов.&lt;br /&gt;&lt;br /&gt;В методе Гаусса-Зейделя мы последовательно элемент за элементом вычисляем вектор p&lt;sup&gt;(k+1)&lt;/sup&gt;. При это там где, согласно формуле А, нам нужно использовать значение p&lt;sup&gt;(k)&lt;/sup&gt;[i] мы используем p&lt;sup&gt;(k+1)&lt;/sup&gt;[i], если этот элемент вектора уже был вычислен.&lt;br /&gt;&lt;br /&gt;Согласно экспериментам этот метод способен сократить необходимое количество итераций на 40%. Его недостаток в том, что его достаточно сложно вычислять параллельно.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Методы экстраполяции (Extrapolation methods)&lt;/h4&gt;&lt;br /&gt;В этой группе методов мы проделываем некоторое количество d обычных итераций метода степеней. Затем на основе результатов этих итераций строим аппроксимацию решения и используем её вместо p&lt;sup&gt;(k)&lt;/sup&gt; для следующей итерации. Через следующие d итераций повторяем трюк. И так далее пока алгоритм не сойдётся.&lt;br /&gt;&lt;br /&gt;Исследователям удавалось достичь сокращения необходимого количества итераций на 30%.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Адаптивный метод (Adaptive method)&lt;/h4&gt;&lt;br /&gt;Этот метод основан на наблюдении, что значительная часть элементов вектора p сходится гораздо быстрее остальных и затем почти не меняется.  Ускорение в этом методе достигается за счёт того, что мы не пересчитываем значения таких элементов.&lt;br /&gt;&lt;br /&gt;Если в какой-то момент k для некоторого элемента i обнаруживается что p&lt;sup&gt;(k+1)&lt;/sup&gt;[i]&amp;nbsp;-&amp;nbsp;p&lt;sup&gt;(k)&lt;/sup&gt;[i] меньше определённого порога, мы считаем, что значение PageRank для страницы i найдено и более не пересчитываем i-тый элемент вектора p.&lt;br /&gt;&lt;br /&gt;Исследователям удавалось достичь сокращения времени работы метода степеней на 20% при помощи этого трюка.&lt;br /&gt;&lt;br /&gt;Однако данный метод требует периодически переупорядочивать данные, чтобы избежать вычисления тех элементов, значения которых считаются уже найденными. Поэтому адаптивный метод плохо подходит для больших графов – переупорядочить огромный объём данных становится слишком дорогой задачей.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Метод блочной структуры (Block Structure Method)&lt;/h4&gt;&lt;br /&gt;Web имеет блочную структуру. Это открытие столь интересно, что я намерен посвятить ему отдельный пост. Там же и обсудим этот метод.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;UPD:&lt;/b&gt; &lt;a href="http://ornitos.blogspot.com/2009/03/web.html"&gt;пост о блочной структуре web&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Численные методы&lt;/h3&gt;&lt;br /&gt;Вычисляя значение PageRank, мы ищем такой вектор p, что&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://3.bp.blogspot.com/_k7xapXUhZ_s/SbqTErJYJjI/AAAAAAAAACQ/3fIwwj6x_ec/s1600/pr2.png" /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Это выражение является так называемой собственной системой, а p – собственный вектор матрицы A. Задача поиска собственного вектора может быть представлена &lt;a href="http://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0_%D0%BB%D0%B8%D0%BD%D0%B5%D0%B9%D0%BD%D1%8B%D1%85_%D0%B0%D0%BB%D0%B3%D0%B5%D0%B1%D1%80%D0%B0%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D1%85_%D1%83%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B9"&gt;системой линейных уравнений&lt;/a&gt;. В нашем случае это будет огромная, но всё же обычная система, которая может быть решена при помощи &lt;a href="http://ru.wikipedia.org/wiki/%D0%A7%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D1%8B"&gt;численных методов&lt;/a&gt; линейной алгебры.&lt;br /&gt;&lt;br /&gt;Тем не менее, вычисление PageRank численными методами ещё находится в экспериментальной области. Каковы будут характеристики и свойства этих методов на реальных графах web пока не понятно.&lt;br /&gt;&lt;br /&gt;Стоит отметить, что существуют уже готовые решения для параллельного вычисления крупных линейных систем.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Параллелизация&lt;/h3&gt;&lt;br /&gt;Вычисление PageRank параллельно на нескольких машинах позволяет существенно ускорить работу.&lt;br /&gt;&lt;br /&gt;По сути методы параллелизации  можно разделит на два типа.&lt;br /&gt;&lt;br /&gt;Первые разделяют граф страниц на плотно связные компоненты – группы страниц плотно связанных ссылками между собой и имеющие относительно немного ссылок на страницы вне группы. PageRank для каждой такой группы вычисляется параллельно. Процессы/потоки периодически обмениваются информацией, когда дело доходит до ссылок между страницами разных групп.&lt;br /&gt;&lt;br /&gt;Ко второму типу относятся методы, использующие блочную структуру web. О них мы поговорим в уже обещанном выше посте о блочной структуре.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;UPD:&lt;/b&gt; &lt;a href="http://ornitos.blogspot.com/2009/03/web.html"&gt;пост о блочной структуре web&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Оптимизация ввода-вывода&lt;/h3&gt;&lt;br /&gt;Это довольно интересная тема, которую я приберегу для одного из следующих постов. Я представлю три алгоритма, которые будут интересны не только с точки зрения вычисления PageRank, но и вообще с точки зрения обработки больших объёмов информации.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Эволюция графа&lt;/h3&gt;&lt;br /&gt;Довольно естественной кажется идея не пересчитывать PageRank для всех страниц целиком, а найти способ обновлять его по мере эволюции графа страниц (по мере эволюции web).&lt;br /&gt;&lt;br /&gt;В «Incremental Page Rank Computation on Evolving Graphs» Prasanna Desikan и др. предлагают следующий способ.&lt;br /&gt;&lt;br /&gt;Сперва выделить часть графа, состоящую из страниц, до которых не существует путей от новых страниц, исчезнувших страниц, либо страниц, ссылки которых были изменены. Удалить эту часть графа, оставив только граничные узлы (т.к. они влияют на PageRank оставшихся страниц). Посчитать PageRank для оставшегося графа. Затем отмасштабировать значения PageRank с учётом общего количества страниц&amp;nbsp;– т.к. количество страниц влияет на часть PageRank, получаемую за счёт телепортации.&lt;br /&gt;&lt;br /&gt;Замечу, что полученный в результате PageRank не является точным, а всё же некой аппроксимацией.&lt;br /&gt;&lt;br /&gt;По различным данным от 25% до 40% ссылок между web-страницами меняются в интернет в течение недели. Такая скорость изменения, на мой взгляд, оправдывает полный пересчёт PageRank всех страниц.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Персонализация&lt;/h3&gt;&lt;br /&gt;Представление о важности той или ной страницы во многом субъективно. То, что покажется одному отбросом, другой сочтёт изумрудом. Пусть есть очень качественная страница об игре керлинг, но я совершенно не хочу, чтобы она вылезала лично мне в топ. Чтобы учитывать в ранжировании интересы конкретного человека был придуман персонализированный PageRank.&lt;br /&gt;&lt;br /&gt;Выбирается какое-то количество категорий, по которым можно классифицировать тематику тех или иных страниц (или сайтов). Например: культура, спорт, политика и т.п.&lt;br /&gt;&lt;br /&gt;Пусть T[j] – множество страниц, принадлежащих к категории j (или расположенных на сайте, принадлежащем к данной категории).&lt;br /&gt;&lt;br /&gt;Для каждой категории формируется особый вектор телепортации v (см. главу Телепортация).&lt;br /&gt;&lt;br /&gt;v[i] очень мало, если страница i не принадлежит T[j], и значительно больше если принадлежит.&lt;br /&gt;&lt;br /&gt;Для каждого тематического вектора телепортации вычисляется тематический PageRank p&lt;sub&gt;j&lt;/sub&gt;. Вычислить сто тематических PageRank для ста категорий вполне реально.&lt;br /&gt;&lt;br /&gt;Допустим, у нас есть вектор k, сумма элементов которого равна единице. Значение k[j] отражает степень заинтересованности пользователя (реального, а не того из модели блуждания) в категории j.&lt;br /&gt;&lt;br /&gt;Степень заинтересованности пользователя может быть указана явно, или она может быть сохранена в его профиле. Или она может быть выведена исходя из того, какие слова входят в запрос. Например, если запрос содержит слово &lt;a href="http://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D1%80%D0%B0%D0%B2%D0%B5%D0%B4%D0%BB%D0%B8%D0%B2%D0%B0%D1%8F_%D1%82%D0%BE%D1%80%D0%B3%D0%BE%D0%B2%D0%BB%D1%8F"&gt;fairtrade&lt;/a&gt; то можно вывести, что пользователь заинтересован на 0.4 в теме общество, на 0.4 в теме экономика и на 0.2 в теме политика.&lt;br /&gt;&lt;br /&gt;Во время ранжирования результатов запроса пользователя для страниц используется следующее итоговое значение PageRank:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;k[0] * p&lt;sub&gt;0&lt;/sub&gt; + k[1] * p&lt;sub&gt;1&lt;/sub&gt; + … + k[n] * p&lt;sub&gt;n&lt;/sub&gt; , где n – количество категорий&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Таким образом, рейтинг страницы будет зависеть от того, что реально интересно пользователю.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Темы, которые будут рассмотрены в следующих постах&lt;/h3&gt;&lt;br /&gt;&lt;h4&gt;Оптимизация ввода-вывода&lt;/h4&gt;&lt;br /&gt;Это довольно интересная тема, которую я приберегу для одного из следующих постов. Я представлю три алгоритма, которые будут интересны не только с точки зрения вычисления PageRank, но и вообще с точки зрения обработки больших объёмов информации.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Siterank&lt;/h4&gt;&lt;br /&gt;&lt;b&gt;UPD:&lt;/b&gt; Эта тема освещена в &lt;a href="http://ornitos.blogspot.com/2009/03/web.html"&gt;посте о блочной структуре web&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7460359136037979439-2923120312309016038?l=ornitos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ornitos.blogspot.com/feeds/2923120312309016038/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7460359136037979439&amp;postID=2923120312309016038' title='Комментарии: 7'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/2923120312309016038'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/2923120312309016038'/><link rel='alternate' type='text/html' href='http://ornitos.blogspot.com/2009/03/pagerank.html' title='Развитие PageRank'/><author><name>Орнитос</name><uri>http://www.blogger.com/profile/12064108298006689502</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://bp2.blogger.com/_k7xapXUhZ_s/SJPXQ06KswI/AAAAAAAAAAM/2K6WJemR5iE/s1600-R/000c9pyk'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_k7xapXUhZ_s/SblC93qpCbI/AAAAAAAAABg/oBztago6Fkg/s72-c/Screenshot.ru.png' height='72' width='72'/><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7460359136037979439.post-1361493304463556662</id><published>2009-02-18T11:26:00.002+03:00</published><updated>2009-02-18T11:29:34.834+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='компьютерное зрение'/><title type='text'>Насколько похожи лица людей?</title><content type='html'>Наткнулся на весьма интересные исследования в области компьютерного зрения, касающиеся распознавания человеческих лиц. &lt;br /&gt;&lt;br /&gt;Рассматриваются цифровые полутоновые изображения. Такие изображения представимы матрицей целых чисел. Операциями сложения и умножения на число для изображений являются соответствующие матричные операции. &lt;br /&gt;&lt;br /&gt;Можно найти ортонормированное базисное множество изображений &lt;b&gt;B&lt;/b&gt;.&lt;br /&gt;&lt;div style="text-align:center"&gt;&lt;br /&gt;&lt;b&gt;B&lt;/b&gt; = {F1, F2, ... , Fm}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Такое, что для любого изображения &lt;b&gt;I&lt;/b&gt;j из множества n изображений (n &gt;&gt; m):&lt;br /&gt;&lt;div style="text-align:center"&gt;&lt;br /&gt;&lt;img src="http://pics.livejournal.com/kibungo/pic/000252zq" width="230" height="129" border='0'/&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;I&lt;/b&gt;j со штрихом — это аппроксимация исходного изображения &lt;b&gt;I&lt;/b&gt;j в виде линейной комбинации m базисных изображений.&lt;br /&gt;&lt;br /&gt;Т.е. при помощи линейной комбинации m базисных изображений мы можем с некоторой точностью получить любое из n изображений некоторого множества. &lt;br /&gt;&lt;br /&gt;Так причём же здесь человеческие лица... &lt;br /&gt;&lt;br /&gt;В нескольких исследовательских проектах было продемонстрировано, что от 15 до 20 базисных изображений достаточно, для представления базы данных с изображениями человеческих лиц. То есть любое человеческое лицо можно представить набором всего 15-20 чисел (!). В любой момент по этим числам можно получить фотографическое изображение  человеческого лица.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7460359136037979439-1361493304463556662?l=ornitos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ornitos.blogspot.com/feeds/1361493304463556662/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7460359136037979439&amp;postID=1361493304463556662' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/1361493304463556662'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/1361493304463556662'/><link rel='alternate' type='text/html' href='http://ornitos.blogspot.com/2009/02/blog-post_18.html' title='Насколько похожи лица людей?'/><author><name>Орнитос</name><uri>http://www.blogger.com/profile/12064108298006689502</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://bp2.blogger.com/_k7xapXUhZ_s/SJPXQ06KswI/AAAAAAAAAAM/2K6WJemR5iE/s1600-R/000c9pyk'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7460359136037979439.post-2343509862700824621</id><published>2009-02-17T21:13:00.006+03:00</published><updated>2009-03-15T19:31:35.151+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Как нужно использовать Hibernate?</title><content type='html'>Когда я стал внедрять Hibernate, понял, что существует определённый стандартный способ его использования. У меня есть подозрение, что его специально не выставляют на показ начинающим пользователям, дабы не отпугнуть их тем, что на архитектуру их приложения накладываются новые требования со стороны тех средств, использование которых хотелось бы видеть прозрачным. &lt;br /&gt;&lt;br /&gt;Стандартный способ использования Hibernate — паттерн &lt;a href="http://www.hibernate.org/43.html"&gt;Session per View&lt;/a&gt;. Согласно этому паттерну использование Hibernate должно выглядеть следующим образом: открывается сессия, получаются все необходимые данные, производятся вычисления, строится представление, сессия закрывается. После закрытия сессии никакие данные, полученные с момента её открытия, более не используются. &lt;br /&gt;&lt;br /&gt;Не обязательно должно строится представление. Вместо него может формироваться ответ сервера на запрос, или реакция на событие. Важно то, что все полученные данные не используются после выполнения работы и не предаются другим потокам. &lt;br /&gt;&lt;br /&gt;До тех пор пока вы используете объекты, полученные из Hibernate, вы должны иметь открытой сессию, в которой были получены эти объекты (или к которой были привязаны), и иметь активную транзакцию!  Использовать эти объекты можно только в однопоточной среде! Иначе со стороны Hibernate возможны ошибки.&lt;br /&gt;&lt;br /&gt;Обычно, создаётся некоторый перехватчик, срабатывающий при получении запроса. Он открывает сессию и делает её доступной для всех классов, методы которых выполняются в данном потоке обработки (что-то типа ThreadLocal). &lt;br /&gt;&lt;br /&gt;Может быть, такого способа работы часто бывает достаточно, но, на мой взгляд, такой костюмчик жмёт.&lt;br /&gt;&lt;br /&gt;Т.е. объекты, полученные из Hibernate — не совсем обычные POJO. Хоть об этом и уверяют на официальном сайте проекта. В чём же их отличие мы узнаем далее. &lt;br /&gt;&lt;br /&gt;Начиная с Hibernate 3, везде, где только можно, выполняется ленивая загрузка, если явно не указано обратное. При помощи &lt;a href="http://asm.objectweb.org/"&gt;ASM&lt;/a&gt;'а Hibernate на лету генерирует байт код прокси-объектов и экранирует ими связи запрашиваемых объектов. За счёт этих прокси части объекта подгружаются по мере необходимости. &lt;br /&gt;&lt;br /&gt;Если же сессия была закрыта, а использование объекта продолжается, то, в случае обращения к такому прокси возникает рантаймовое LazyInitializationException. Если же два потока в один момент обратятся к одному прокси, то поведение вовсе не предсказуемо, т.к. прокси используют сессию, а сессия предназначена только для однопоточного использования.&lt;br /&gt;&lt;br /&gt;От ограничений Session per View можно избавиться, если в определённый момент иметь гарантию того, что объект загружен полностью со всеми своими связями. Тогда он станет обычным POJO. Его можно будет использовать после закрытия сессии и использовать многопоточно, если сам объект на это рассчитан.&lt;br /&gt;&lt;br /&gt;Получить такую гарантию можно, если отключить для всех связей этого объекта ленивую загрузку. Это довольно утомительно, т.к. нет способа отключить ленивую загрузку сразу для всего — придётся отключать её для каждого класса отдельно. &lt;br /&gt;&lt;br /&gt;Второй способ — написать метод, который бы в необходимый момент мог вызвать полную инициализацию всего графа объекта. В Hibernate нет собственного такого метода, но он позволяет его реализовать: &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;br /&gt;public class LoadDragoon {&lt;br /&gt;&lt;br /&gt;    private SessionFactory sessionFactory;&lt;br /&gt;&lt;br /&gt;    private static Logger logger = Logger.getLogger(LoadDragoon.class.getName());&lt;br /&gt;&lt;br /&gt;    public LoadDragoon(SessionFactory sessionFactory) {&lt;br /&gt;        this.sessionFactory = sessionFactory;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void forceLoad(Object obj) throws HibernateException {&lt;br /&gt;        if (obj == null) {&lt;br /&gt;            return;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        Class entityClass = Hibernate.getClass(obj);&lt;br /&gt;&lt;br /&gt;        if (!Hibernate.isInitialized(obj)) {&lt;br /&gt;            logger.finest("Force initialization of " + entityClass.getName());&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        Hibernate.initialize(obj);&lt;br /&gt;        ClassMetadata md = sessionFactory.getClassMetadata(entityClass);&lt;br /&gt;&lt;br /&gt;        if (md == null) {&lt;br /&gt;            return;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        String[] propertyNames = md.getPropertyNames();&lt;br /&gt;&lt;br /&gt;        for (String propertyName : propertyNames) {&lt;br /&gt;            Type propertyType = md.getPropertyType(propertyName);&lt;br /&gt;&lt;br /&gt;            if (propertyType.isEntityType()) {&lt;br /&gt;                Object assoc = md.getPropertyValue(obj, propertyName, &lt;br /&gt;                    EntityMode.POJO);&lt;br /&gt;                forceLoad(assoc);&lt;br /&gt;            } else if (propertyType.isCollectionType()) {&lt;br /&gt;                Object container = md.getPropertyValue(obj, propertyName, &lt;br /&gt;                    EntityMode.POJO);&lt;br /&gt;                Hibernate.initialize(container);&lt;br /&gt;&lt;br /&gt;                if (container instanceof Map) {&lt;br /&gt;                    Map map = (Map) container;&lt;br /&gt;&lt;br /&gt;                    for (Map.Entry entry : map.entrySet()) {&lt;br /&gt;                        forceLoad(entry.getKey());&lt;br /&gt;                        forceLoad(entry.getValue());&lt;br /&gt;                    }&lt;br /&gt;                } else {&lt;br /&gt;                    Collection collection = (Collection) container;&lt;br /&gt;&lt;br /&gt;                    for (Object element : collection) {&lt;br /&gt;                        forceLoad(element);&lt;br /&gt;                    }&lt;br /&gt;                }  &lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7460359136037979439-2343509862700824621?l=ornitos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ornitos.blogspot.com/feeds/2343509862700824621/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7460359136037979439&amp;postID=2343509862700824621' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/2343509862700824621'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/2343509862700824621'/><link rel='alternate' type='text/html' href='http://ornitos.blogspot.com/2009/02/hibernate.html' title='Как нужно использовать Hibernate?'/><author><name>Орнитос</name><uri>http://www.blogger.com/profile/12064108298006689502</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://bp2.blogger.com/_k7xapXUhZ_s/SJPXQ06KswI/AAAAAAAAAAM/2K6WJemR5iE/s1600-R/000c9pyk'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7460359136037979439.post-7971726742513048965</id><published>2009-02-17T21:00:00.008+03:00</published><updated>2009-03-15T19:29:44.858+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Злые модули</title><content type='html'>Есть такая засада в C++, Java и, вероятно, в некоторых других языках. Функции, вычисляющие модуль целого числа (std::abs в С++ или Math.abs в Java), способны возвращать отрицательные значения!&lt;br /&gt;&lt;br /&gt;Например, число типа long имеет максимальное значение 2147483647, а минимальное — -2147483648. Соответственно, модуль минимального числа типа long не может быть представлен типом long — функция просто молча вернёт переданное в неё отрицательное значение.&lt;br /&gt;&lt;pre&gt;&lt;code class="cpp"&gt;&lt;br /&gt;cout &lt;&lt; "min = " &lt;&lt; numeric_limits&lt;long&gt;::min() &lt;&lt; " ; max = " &lt;&lt;&lt;br /&gt;    numeric_limits&lt;long&gt;::max() &lt;&lt; endl; &lt;br /&gt;cout &lt;&lt; "abs(min) = " &lt;&lt; abs(numeric_limits&lt;long&gt;::min());&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;Вывод:&lt;br /&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;br /&gt;min = -2147483648 ; max = 2147483647&lt;br /&gt;abs(min) = -2147483648&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;На это можно однажды крепко налететь...&lt;br /&gt;&lt;br /&gt;В SmallTalk, к слову, такой проблемы нет. Т.к. ему вообще не свойственна проблема переполнения целых чисел. LargePositiveInteger, имеет неограниченый размер. А операции над ограниченным по размеру SmallInteger,  при необходимости автоматически приведут к созданию LargePositiveInteger и использованию его в качестве результата.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7460359136037979439-7971726742513048965?l=ornitos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ornitos.blogspot.com/feeds/7971726742513048965/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7460359136037979439&amp;postID=7971726742513048965' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/7971726742513048965'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/7971726742513048965'/><link rel='alternate' type='text/html' href='http://ornitos.blogspot.com/2009/02/blog-post_4295.html' title='Злые модули'/><author><name>Орнитос</name><uri>http://www.blogger.com/profile/12064108298006689502</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://bp2.blogger.com/_k7xapXUhZ_s/SJPXQ06KswI/AAAAAAAAAAM/2K6WJemR5iE/s1600-R/000c9pyk'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7460359136037979439.post-1242402891460297862</id><published>2009-02-17T20:48:00.001+03:00</published><updated>2009-02-17T20:48:55.257+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='разработка'/><title type='text'>synchronized</title><content type='html'>Мужик подходит к кассе, чтобы сделать покупку. Говорит: "Девушка, дайте мне килограммчик картошки, полкило помидоров и ещё вот этот..." В этот момент встревает другой мужчина: "Девушка, а почём у вас перец?!" Девушка достаёт нож и режет горло обоим. Объекты, хорошо работающие в однопоточной среде, могут совершенно непредсказуемо повести себя в многопоточной.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7460359136037979439-1242402891460297862?l=ornitos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ornitos.blogspot.com/feeds/1242402891460297862/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7460359136037979439&amp;postID=1242402891460297862' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/1242402891460297862'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/1242402891460297862'/><link rel='alternate' type='text/html' href='http://ornitos.blogspot.com/2009/02/synchronized.html' title='synchronized'/><author><name>Орнитос</name><uri>http://www.blogger.com/profile/12064108298006689502</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://bp2.blogger.com/_k7xapXUhZ_s/SJPXQ06KswI/AAAAAAAAAAM/2K6WJemR5iE/s1600-R/000c9pyk'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7460359136037979439.post-8902496829422390679</id><published>2009-02-17T20:44:00.000+03:00</published><updated>2009-02-17T20:46:21.304+03:00</updated><title type='text'>Джайнистская логика</title><content type='html'>Программисты обычно работают с бинарной логикой, рассматривающей два типа суждений: утвердительные и отрицательные. Иногда приходится работать с тернарной логикой, добавляющей третье суждение: "неизвестно". &lt;br /&gt;&lt;br /&gt;В &lt;a href="http://ru.wikipedia.org/wiki/%D0%94%D0%B6%D0%B0%D0%B9%D0%BD%D0%B8%D0%B7%D0%BC"&gt;джайнизме&lt;/a&gt; же, введена семеричная логика! Джайнисты справедливо считают, что истиность любого суждения относительна. Каждое суждение порождено определёнными условиями и, следовательно, ограничено. Различные суждения об одном и том же предмете могут быть справедливыми каждое со своей точки зрения. Это воззрение во многом сформировало логику джайнистов.&lt;br /&gt;&lt;br /&gt;Таким образом, признаётся семь типов условного суждения. Помимо утверждения (A обладает свойством B), отрицания (A не обладает свойством B), вводятся ещё пять:&lt;br /&gt;&lt;br /&gt;1) А обладает свойством B, а также не обладает свойством B;&lt;br /&gt;2) A есть неописуемое;&lt;br /&gt;3) А обладает свойством B, и является неописуемым;&lt;br /&gt;4) А не обладает свойством B, и является неописуемым;&lt;br /&gt;5) А обладает свойством B, а также не обладает свойством B и является неописуемым;&lt;br /&gt;&lt;br /&gt;К первому суждению прибегают, когда объект в некоторых условиях обладает определённым свойством, а в некоторых не обладает. В том случае, когда мы вынуждены одновременно приписать объекту такие характерные признаки, которые не совместимы, будучи противоположными или противоречивыми, объект есть неописуемое. Последние три типа суждений образуются посредством комбинаций. 3-е по списку утверждение означает, что объект может обладать некоторым свойством, но безотносительно к контексту (например, времени или пространству) ему не может быть приписан данный признак. 4-е и 5-е вводятся аналогично.&lt;br /&gt;&lt;br /&gt;Это краткая характеристика. Тему можно было бы развить.&lt;br /&gt;&lt;br /&gt;Думается, что логика джайнистов может быть выражена средствами классической логики. Мыслить же непосредственно их суждениями я бы не смог...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7460359136037979439-8902496829422390679?l=ornitos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ornitos.blogspot.com/feeds/8902496829422390679/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7460359136037979439&amp;postID=8902496829422390679' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/8902496829422390679'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/8902496829422390679'/><link rel='alternate' type='text/html' href='http://ornitos.blogspot.com/2009/02/blog-post_2120.html' title='Джайнистская логика'/><author><name>Орнитос</name><uri>http://www.blogger.com/profile/12064108298006689502</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://bp2.blogger.com/_k7xapXUhZ_s/SJPXQ06KswI/AAAAAAAAAAM/2K6WJemR5iE/s1600-R/000c9pyk'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7460359136037979439.post-7356700750240064150</id><published>2009-02-17T20:33:00.003+03:00</published><updated>2009-02-17T20:38:48.712+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Собака</title><content type='html'>Забавная картинка из книги Your brain on java издательства Oreilly.&lt;br /&gt;&lt;br /&gt;Картинка расположена в контексте разговора о коллекциях, генериках и преобразовании типов:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align:center"&gt;&lt;img src="http://pics.livejournal.com/kibungo/pic/0001rcx9"&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7460359136037979439-7356700750240064150?l=ornitos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ornitos.blogspot.com/feeds/7356700750240064150/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7460359136037979439&amp;postID=7356700750240064150' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/7356700750240064150'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/7356700750240064150'/><link rel='alternate' type='text/html' href='http://ornitos.blogspot.com/2009/02/your-brain-on-java-oreilly.html' title='Собака'/><author><name>Орнитос</name><uri>http://www.blogger.com/profile/12064108298006689502</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://bp2.blogger.com/_k7xapXUhZ_s/SJPXQ06KswI/AAAAAAAAAAM/2K6WJemR5iE/s1600-R/000c9pyk'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7460359136037979439.post-5747173213282786420</id><published>2009-02-17T20:24:00.001+03:00</published><updated>2009-02-17T20:29:46.532+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='разработка'/><title type='text'>Попугаи-киллеры, охотящиеся на овец</title><content type='html'>Цитата из книги &lt;a href="http://en.wikipedia.org/wiki/The_Pragmatic_Programmer"&gt;"Программист-прагматик"&lt;/a&gt; [Эндрю Хант, Дэид Томас]:&lt;br /&gt;&lt;br /&gt;"Когда вы начинаете некий проект, придумайте имя для проектной команды, в идеале -- нечто из ряда вон выходящее. В прошлом мы называли проекты в честь попугаев-киллеров, охотящихся на овец, оптических обманов и мифических городов. Потратьте полчаса на придумывание самого идиотского брэнда и используйте его в ваших служебных записках и отчётах. В разговорах с людьми свободно упоминайте название вашей команды"&lt;br /&gt;&lt;br /&gt;Безусловно стоит взять эту рекомендацию на вооружение!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7460359136037979439-5747173213282786420?l=ornitos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ornitos.blogspot.com/feeds/5747173213282786420/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7460359136037979439&amp;postID=5747173213282786420' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/5747173213282786420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/5747173213282786420'/><link rel='alternate' type='text/html' href='http://ornitos.blogspot.com/2009/02/blog-post_8199.html' title='Попугаи-киллеры, охотящиеся на овец'/><author><name>Орнитос</name><uri>http://www.blogger.com/profile/12064108298006689502</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://bp2.blogger.com/_k7xapXUhZ_s/SJPXQ06KswI/AAAAAAAAAAM/2K6WJemR5iE/s1600-R/000c9pyk'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7460359136037979439.post-6892347467743875540</id><published>2009-02-17T20:14:00.003+03:00</published><updated>2009-02-17T20:24:33.171+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='алгоритмы'/><title type='text'>Дихотомия</title><content type='html'>Довольно любопытно, что &lt;a href="http://ru.wikipedia.org/wiki/Двоичный_поиск"&gt;Двоичный поиск&lt;/a&gt; имеет репутацию трудного для реализации и понимания алгоритма. &lt;br /&gt;&lt;br /&gt;В "The Art of Computer Programming" Дональда Кнута сообщается, что двоичный поиск впервые вызвал дискуссию в 1946 году, и вплоть до 1962 г. (!) никому не удавалось опубликовать алгоритм, корректно работающий с массивами длины, отличной от 2^n - 1.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7460359136037979439-6892347467743875540?l=ornitos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ornitos.blogspot.com/feeds/6892347467743875540/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7460359136037979439&amp;postID=6892347467743875540' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/6892347467743875540'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/6892347467743875540'/><link rel='alternate' type='text/html' href='http://ornitos.blogspot.com/2009/02/blog-post_17.html' title='Дихотомия'/><author><name>Орнитос</name><uri>http://www.blogger.com/profile/12064108298006689502</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://bp2.blogger.com/_k7xapXUhZ_s/SJPXQ06KswI/AAAAAAAAAAM/2K6WJemR5iE/s1600-R/000c9pyk'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7460359136037979439.post-9204099190489552788</id><published>2009-02-17T19:57:00.002+03:00</published><updated>2009-02-17T20:11:46.106+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='компьютерное зрение'/><title type='text'>О глазах</title><content type='html'>Известно, что личность человека можно идентифицировать по радужной оболочке глаза. Однако, прежде чем стали внедряться системы, использующие этот факт, требовалось выяснить, насколько различаются радужные оболочки глаз разных людей. Требовалось найти надёжный способ вычисления по снимку человеческого глаза такого идентификатора, который был бы уникален. &lt;br /&gt;&lt;br /&gt;&lt;div style="text-align:center"&gt;&lt;img src="http://pics.livejournal.com/kibungo/pic/0002ekps" alt="глаз" border='0'/&gt;&lt;/div&gt;&lt;br /&gt;В системе Sensar Secure System, предназначенной для идентификации пользователей банкоматов, по радужной оболочке вычисляется 2048-ми битный код. Значение каждого бита определяется путём вычисления корреляции двумерного вейвлета Габора с изображением радужной оболочки в 1024-х точках изображения. Комплексозначное корреляционное значение преобразуется в два бита кода. &lt;br /&gt;&lt;br /&gt;Чтобы убедиться в пригодности такого способа, для кодов достаточно большого количества пар глаз были вычислены расстояния Хэмминга. Расстояние Хэмминга между двумя кодами это количество несовпадающих бит при их сравнении. То есть, это значение показывает насколько различаются радужные оболочки.&lt;br /&gt;&lt;br /&gt;Было получено, что коды для двух глаз одного человека столь же независимы и столь же отличаются друг от друга как коды глаз совершенно разных людей. Иными словами, текстуры радужных оболочек своих собственных глаз различны и некоррелируют между собой!&lt;br /&gt;&lt;br /&gt;Также любопытно следующее. Зрачок и радужная оболочка имеют круговую форму, но центры этих окружностей не совпадают.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7460359136037979439-9204099190489552788?l=ornitos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ornitos.blogspot.com/feeds/9204099190489552788/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7460359136037979439&amp;postID=9204099190489552788' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/9204099190489552788'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/9204099190489552788'/><link rel='alternate' type='text/html' href='http://ornitos.blogspot.com/2009/02/blog-post.html' title='О глазах'/><author><name>Орнитос</name><uri>http://www.blogger.com/profile/12064108298006689502</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://bp2.blogger.com/_k7xapXUhZ_s/SJPXQ06KswI/AAAAAAAAAAM/2K6WJemR5iE/s1600-R/000c9pyk'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7460359136037979439.post-6891142742325741503</id><published>2008-08-02T09:37:00.009+04:00</published><updated>2008-08-03T11:29:01.289+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>+=</title><content type='html'>Обычно считают, что в Java x += y (и аналогично -=, *= и т.п.) является лишь сокращённой записью x = x + y. Но это не вся правда. Посмотрим на следующий пример:&lt;br /&gt;&lt;pre&gt;&lt;code class="java"&gt;short s = 1;&lt;br /&gt;s = s + 1;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;Этот код не компилируется, несмотря на то, что 1 + 1 = 2 представимо типом short! Причина не только в том, что литерал 1 имеет тип int. Не будет компилироваться и такой вариант:&lt;br /&gt;&lt;pre&gt;&lt;code class="java"&gt;short s1 = 1;&lt;br /&gt;short s2 = 1;&lt;br /&gt;s2 = s2 + s1;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;То же самое можно было бы написать с типами byte и char. Причина в том, что результат арифметических операций с использованием типов short, byte, char имеет тип int. Мотивация этого такова: к примеру, сумма двух byte может легко быть больше того, что влезет в byte. Но код можно исправить следующим образом без явного преобразования типов:&lt;br /&gt;&lt;pre&gt;&lt;code class="java"&gt;short s = 1;&lt;br /&gt;s += 1;&lt;br /&gt;&lt;br /&gt;short s1 = 1;&lt;br /&gt;short s2 = 1;&lt;br /&gt;s2 += s1;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;На самом деле x += y, вопреки распространённому мнению, эквивалентно&lt;br /&gt;&lt;pre&gt;&lt;code class="java"&gt;x = (тип x) (x + y);&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;Т.е. включает в себя преобразование результата к типу x. То же самое верно и для операторов -=, *= и т.п.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7460359136037979439-6891142742325741503?l=ornitos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ornitos.blogspot.com/feeds/6891142742325741503/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7460359136037979439&amp;postID=6891142742325741503' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/6891142742325741503'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/6891142742325741503'/><link rel='alternate' type='text/html' href='http://ornitos.blogspot.com/2008/08/blog-post_02.html' title='+='/><author><name>Орнитос</name><uri>http://www.blogger.com/profile/12064108298006689502</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://bp2.blogger.com/_k7xapXUhZ_s/SJPXQ06KswI/AAAAAAAAAAM/2K6WJemR5iE/s1600-R/000c9pyk'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7460359136037979439.post-5087133943488050000</id><published>2008-08-02T08:14:00.006+04:00</published><updated>2008-08-02T10:53:22.153+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Литералы</title><content type='html'>Известно, что в java литералы целых чисел имеют по умолчанию тип int, а литералы чисел с плавающей точкой – double. Но, помимо различий в типе, есть ещё некоторое различие в поведении. &lt;br /&gt;&lt;br /&gt;Не удивительно, что эта строчка при компиляции вызывает ошибку из-за несовместимости типов float и double:&lt;br /&gt;&lt;pre&gt;&lt;code class="java"&gt;float f = 25.2; // слева float, справа double&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;И, казалось бы, следующий пример тоже не должен был бы компилироваться, ведь int не преобразуется в byte неявно:&lt;br /&gt;&lt;pre&gt;&lt;code class="java"&gt;byte b = 127; // слева byte, справа int&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;Однако последний пример компилируется! В этом случае, если значение справа представимо типом byte (от -128 до 127), компилятор сам выполнит преобразование. Аналогично, без явного преобразования, целочисленные литералы можно присваивать типам short и char.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7460359136037979439-5087133943488050000?l=ornitos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ornitos.blogspot.com/feeds/5087133943488050000/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7460359136037979439&amp;postID=5087133943488050000' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/5087133943488050000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/5087133943488050000'/><link rel='alternate' type='text/html' href='http://ornitos.blogspot.com/2008/08/blog-post.html' title='Литералы'/><author><name>Орнитос</name><uri>http://www.blogger.com/profile/12064108298006689502</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://bp2.blogger.com/_k7xapXUhZ_s/SJPXQ06KswI/AAAAAAAAAAM/2K6WJemR5iE/s1600-R/000c9pyk'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7460359136037979439.post-7080247460283902268</id><published>2007-01-29T15:50:00.005+03:00</published><updated>2008-08-02T08:14:03.260+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>Проблема 2038</title><content type='html'>Стандартная библиотека C++ не предоставляет подходящего типа данных для дат. C++ наследует структуры и функции для работы с датами и временем от C.&lt;br /&gt;&lt;br /&gt;В C для представления даты/времени используется тип time_t. Это зависимый от реализации арифметический тип (в разных реализациях C/C++ может представлять различный диапазон значений), представляющий временной период (интервал времени) с точностью до одной секунды.&lt;br /&gt;&lt;br /&gt;В большинстве реализаций time_t позволяет представить наибольший интервал времени в 2147483648 секунд. Это примерно 68 лет. Также в большинстве реализаций для представления текущего времени в качестве начала отсчёта используют 0:00:00 1&amp;nbsp;января 1970 года.&lt;br /&gt;&lt;br /&gt;Т.е. в большинстве популярных реализаций невозможно представить даты и времена после 2038 года, и большая часть программного обеспечения перестанет работать, если заранее не принять меры!&lt;br /&gt;&lt;br /&gt;В Visual C++ 2005 time_t является синонимом __time64_t, т.е. способен представить больший интервал и не подвержен ошибке 2038. Однако, это препятствует переносимости кода. Чтобы использовать обычный 32-битный time_t следует определить _USE_32BIT_TIME_T.&lt;br /&gt;&lt;br /&gt;В &lt;a href="http://www.boost.org"&gt;Boost&lt;/a&gt; есть хорошая библиотека &lt;a href="http://www.boost.org/doc/html/date_time.html"&gt;date_time&lt;/a&gt;, не подверженая проблеме 2038. Ожидается, что будущие средства стандартной библиотеки для работы с датой/временем будут основаны на date_time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7460359136037979439-7080247460283902268?l=ornitos.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ornitos.blogspot.com/feeds/7080247460283902268/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7460359136037979439&amp;postID=7080247460283902268' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/7080247460283902268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7460359136037979439/posts/default/7080247460283902268'/><link rel='alternate' type='text/html' href='http://ornitos.blogspot.com/2007/01/2038.html' title='Проблема 2038'/><author><name>Орнитос</name><uri>http://www.blogger.com/profile/12064108298006689502</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://bp2.blogger.com/_k7xapXUhZ_s/SJPXQ06KswI/AAAAAAAAAAM/2K6WJemR5iE/s1600-R/000c9pyk'/></author><thr:total>0</thr:total></entry></feed>
