(UseModWiki소스수정/사용자의견 에 있던 역링크 개선에 관한 얘기를 이쪽으로 옮깁니다. 멍석을 따로 깔아서... ^_^)
sub DoPost {
....
$Text{'text'} = $string;
$Text{'minor'} = $isEdit;
$Text{'newauthor'} = $newAuthor;
$Text{'summary'} = $summary;
$Page{'links'} = &GetLinks();
$Page{'outlinks'} = &GetLinks(1);
$Section{'host'} = &GetRemoteHost(1);
&SaveDefaultText();
....
}
sub DoMaintain {
my ($name, $fname, $data);
print &GetHeader('', T('Maintenance on all pages'), '');
print "<br>";
$fname = "$DataDir/maintain";
if (!&UserIsAdmin()) {
print T('You cannot use maintain.');
print &GetCommonFooter();
return;
} elsif (!&UserIsAdmin()) {
if ((-f $fname) && ((-M $fname) < 0.5)) {
print T('Maintenance not done.'), ' ';
print "<br>", T('(Maintenance can only be done once every 12 hours.)');
print "<br>", T('Remove the "maintain" file or wait.');
print &GetCommonFooter();
return;
}
}
&RequestLock() or die(T('Could not get maintain-lock'));
foreach $name (&AllPagesList()) {
&OpenPage($name);
&OpenDefaultText();
my $message;
if ($message ne ' (deleted)') {
$Page{'links'} = &GetLinks();
$Page{'outlinks'} = &GetLinks(1);
$Page{'revision'} -= 1;
&SavePage($name);
$message .= " - Added links list -";
}
&ExpireKeepFile() unless $message eq ' (deleted)';
print ".... " if ($name =~ m|/|);
print &GetPageLink($name), "\n";
print "$message<br>\n";
}
&WriteStringToFile($fname, "Maintenance done at " . &TimeToText($Now));
&ReleaseLock();
$fname = "$DataDir/editlinks";
if (-f $fname) {
$data = &ReadFileOrDie($fname);
print '<hr>', T('Processing rename/delete commands:'), "<br>\n";
&UpdateLinksList($data, 1, 1);
unlink("$fname.old");
rename($fname, "$fname.old");
}
print &GetCommonFooter();
}
sub GetLinks {
my $mode = @_;
my (@links);
my $temp_text = $Text{'text'};
my $result;
$temp_text =~ s/<html>((.|\n)*?)<\/html>//ig;
$temp_text =~ s/<nowiki>(.|\n)*?\<\/nowiki>//ig;
$temp_text =~ s/<pre>(.|\n)*?\<\/pre>//ig;
$temp_text =~ s/<code>(.|\n)*?\<\/code>//ig;
$temp_text =~ s/(^|\n)\{\{\{[ \t\r\f]*\n((.|\n)*?)\n\}\}\}[ \t\r\f]*\n/ \n/igm;
$temp_text =~ s/(^|\n)\{\{\{([a-zA-Z0-9+]+)(\|(n|\d*|n\d+|\d+n))?[ \t\r\f]*\n((.|\n)*?)\n\}\}\}[ \t\r\f]*\n/ \n/igm;
if ($mode) {
$temp_text =~ s/''+/ /g;
$temp_text =~ s/$InterLinkPattern/push(@links, &StripUrlPunct($1)), ' '/ge;
$temp_text =~ s/''+/ /g;
$temp_text =~ s/$UrlPattern/push(@links, &StripUrlPunct($1)), ' '/ge;
$result = " " . join(' ', @links) . " ";
return $result;
} else {
$temp_text =~ s/$InterLinkPattern//ig;
$temp_text =~ s/$UrlPattern//ig;
$temp_text =~ s/ /_/g;
if ($FreeLinks) {
my $fl = $FreeLinkPattern;
$temp_text =~ s/(\[\[$fl\|[^\]]+\]\])/push(@links, &FreeToNormal($1)), ' '/ge;
$temp_text =~ s/(\[\[$fl\]\])/push(@links, &FreeToNormal($1)), ' '/ge;
}
if ($WikiLinks) {
$temp_text =~ s/$LinkPattern/push(@links, &StripUrlPunct($1)), ' '/ge;
}
$result = " " . join(' ', @links) . " ";
return $result;
}
return ;
}
sub GetPageLinks {
my ($name, $pagelink, $interlink, $urllink) = @_;
my ($text, $out_text, @links);
@links = ();
&OpenPage($name);
&OpenDefaultText();
$text = $Page{'links'};
$out_text = $Page{'outlinks'};
if ($interlink) {
$out_text =~ s/''+/ /g;
$out_text =~ s/$InterLinkPattern/push(@links, &StripUrlPunct($1)), ' '/ge;
} else {
$out_text =~ s/$InterLinkPattern/ /g;
}
if ($urllink) {
$out_text =~ s/''+/ /g;
$out_text =~ s/$UrlPattern/push(@links, &StripUrlPunct($1)), ' '/ge;
} else {
$out_text =~ s/$UrlPattern/ /g;
}
if ($pagelink) {
if ($FreeLinks) {
my $fl = $FreeLinkPattern;
$text =~ s/\[\[$fl\|[^\]]+\]\]/push(@links, &FreeToNormal($1)), ' '/ge;
$text =~ s/\[\[$fl\]\]/push(@links, &FreeToNormal($1)), ' '/ge;
}
if ($WikiLinks) {
$text =~ s/$LinkPattern/push(@links, &StripUrlPunct($1)), ' '/ge;
}
}
return @links;
}
sub DoGetBackSearchLink {
my ($id) = @_;
my @x;
my @split_text;
my ($name, $mainid, $subid);
my $result;
$name = $id;
if ($FreeLinks) {
$name =~ s/ /_/g;
$id =~ s/\+/_/g;
}
($mainid, $subid) = split(/\//,$name);
if ($id eq '') {
&DoIndex();
return;
}
print &GetHeader('', &QuoteHtml(Ts('Search for: %s', $name)), '');
print '<br>';
@x = &SearchBack($mainid, $subid);
@x = sort @x;
&PrintPageList(@x);
print &GetCommonFooter();
}
sub SearchBack {
my ($mainid, $subid) = @_;
my ($name, $temp_name, $temp_sub, @found);
foreach $name (&AllPagesList()) {
($temp_name, $temp_sub) = split (/\//, $name);
if (($name ne $mainid) && ($mainid ne $temp_name)) {
&OpenPage($name);
if ($subid ne "") {
if ($mainid =~ /^$LinkPattern$/) {
if (($subid =~ /^$LinkPattern$/)
&& (($Page{'links'} =~ /\s$mainid\/$subid\s/)
|| ($Page{'links'} =~ /\[\[$mainid\/$subid\]\]/))) {
push(@found, $name);
} elsif ($Page{'links'} =~ /\[\[$mainid\/$subid\]\]/) {
push(@found, $name);
}
} else {
if ($Page{'links'} =~ /\[\[$mainid\/$subid\]\]/) {
push(@found, $name);
}
}
} else {
if ($mainid =~ /^$LinkPattern$/) {
if (($Page{'links'} =~ /\s$mainid\s/)
|| ($Page{'links'} =~ /\[\[$mainid\]\]/)) {
push(@found, $name);
}
} else {
if ($Page{'links'} =~ /\[\[$mainid\]\]/) {
push(@found, $name);
}
}
}
} elsif (($name eq $mainid) || ($mainid eq $temp_name)) {
&OpenPage($name);
if ($subid ne "") {
if ($temp_name =~ /^$LinkPattern$/) {
if (($subid =~ /^$LinkPattern$/)
&& (($Page{'links'} =~ /\s$mainid\/$subid\s/)
|| ($Page{'links'} =~ /\s\/$subid\s/)
|| ($Page{'links'} =~ /\[\[$mainid\/$subid\]\]/)
|| ($Page{'links'} =~ /\[\[\/$subid\]\]/))) {
push(@found, $name);
} else {
if (($Page{'links'} =~ /\[\[$mainid\/$subid\]\]/)
|| ($Page{'links'} =~ /\[\[\/$subid\]\]/)) {
push(@found, $name);
}
}
} else {
if ($subid =~ /^$LinkPattern$/) {
if (($Page{'links'} =~ /\s\/$subid\s/)
|| ($Page{'links'} =~ /\[\[\/$subid\]\]/)) {
push (@found, $name);
}
} else {
if (($Page{'links'} =~ /\[\[$mainid\/$subid\]\]/)
|| ($Page{'links'} =~ /\[\[\/$subid\]\]/)) {
push(@found, $name);
}
}
}
} else {
if ($mainid =~ /^$LinkPattern$/) {
if (($Page{'links'} =~ /\s$mainid\s/)
|| ($Page{'links'} =~ /\[\[$mainid\]\]/)) {
push(@found, $name);
}
} else {
if ($Page{'links'} =~ /\[\[$mainid\]\]/) {
push(@found, $name);
}
}
}
}
}
return @found;
}
sub DoOtherRequest {
if (&GetParam("edit_links", 0)) {
&DoUpdateLinks();
return;
}
$search = &GetParam("search", "");
if (($search ne "") || (&GetParam("dosearch", "") ne "")) {
&DoSearch($search);
return;
}
$search = &GetParam("reverse", "");
if ($search ne "") {
return;
}
if (&GetParam("oldtime", "") ne "") {
}
대충 정리 했습니다. 처음에 GetPageLinks 함수의 어디가 속도를 떨어뜨리는지 전혀 몰라서 삽질을 엄청했습니다. 제대로 알고만 있었다면..ㅜㅡ
사실 GetPageLinks함수만 수정해서 기존의 역링크 소스를 사용하면 되는데, 한게 아까워서 제껄 따로 내려놨습니다.ㅠㅠ
제홈은 페이지수가 적어서, 정확한 속도측정을 하기가 힘드네요.
GetPageLinks에 있던 정규표현식들은 GetLinks라는함수로 옮겼고, 그중에서 urllink나 interlink같이 외부링크를 처리하는 루틴은 모두 없앴습니다.
(외부링크처리루틴을 그대로 살려서 내부링크와 같은 필드안에 저장하는 것은 별로 좋은 일이 아닐 것이고, 굳이 외부링크를 사용해야 한다면, 별도로 외부링크를 위한 필드를 하나 더 만드는 수밖에 없겠습니다.)
테스트하기로는 두개다 별 이상 없이 동작하였습니다. 거북이님 홈에서 테스트가 된다면 좋겠는데....^^a
어쨌거나 다른 특이사항이 생기면 말씀해주세요.
좋은하루 되세요. --
Bab2 2003-2-15 4:19 pm
일단 urllink와 interlink부분을 별도의 필드로 저장하도록 해보겠습니다.
만세... 짝짝짝... 오늘 밤에 테스트해볼께요. 그전에 간단한 사전 설명을 부탁드릴께요, 단답형이니 금방 끝날 거예요 ^^;
- 질문 1 : 다른 준비 작업 없이 위의 것만 하면 되나요? --- 예.
- 질문 2 : 위의 세 개의 박스 중, 첫번째것+두번째것 만 해도 되고, 첫번째것+세번째것 을 해도 된다는 말씀이신가요? (각각 테스트해보지요) --- 예.
- 질문 3 : 1+2 든 1+3 이든 동일하게 링크 목록을 페이지에 저장하는 방식인 건가요? 페이지에 저장되는 목록의 내용까지도 동일한가요? --- 예. 검색방식만 다르고 나머지는 완전히 동일합니다.
- 3-1 : 방식이 다르다면, 차이점을 간단하게.. --- 다르지 않습니다
- 3-2 : 그러면 기존 페이지들은 목록이 없는데 어떻게 되나요? action=maintain 한 번 해주면 되나요? --- 예.
- 질문 4 : 이 페이지를 나중에 통채로 UseModWiki소스수정 아래에 넣기 위해서, 동작 원리를 간단히 적어 주시면 좋겠습니다. (함수 이름 같은 것을 일일이 나열할 필요는 없겠고요. 간략한 개념 정도면 되겠죠. 어느 시점에 뭐를 만들어 어디에 저장하고 언제 참조한다 정도로..)
- 뭐 굳이 동작원리를 따로 설명할 필요도 없을거 같습니다.
- 페이지 안에서 순수한 내부링크만 찾아서 별도의 페이지 정보로 저장하고, 역링크나 action=links를 사용하는 모든 매크로는 이 정보를 참조합니다.(원래는 페이지내용 자체를 ㅤㅎㅜㅀ었죠.)
- 뭐 다른게 있겠습니까, 이정도면 충분할거 같네요. :)
제 홈이 페이지가 370 개인데 (별 것 없이 페이지 수만 많군요 -_-a) 벌써 역링크 속도가 상당히 불만족스러운 지경까지 되었네요. 이 패치가 위력을 발휘하기를 바라마지 않습니다~ :-)
답글 달았습니다. ;)
처음에 의도한 것은 삽질소스가 아니라 위의 것이었습니다. 당시에는 GetPageLinks함수에서 속도를 떨어뜨리는 이유가 문자열 치환이라는 것을 몰랐었고, 삽질소스를 손대다보니 어쩌다 알게 된것이었거든요. ㅠㅠ
그런데, 원래소스에서 action=links&url=1하면 나오게 되는 interlink와 urllink 관련부분은 어떻게 하는게 좋을까요? 10줄 정도만 더 추가해주면 되긴 하거든요. --
Bab2 2003-2-15 5:39 pm
좀 전에... 기존 방식과 위의 두 가지 방식으로 간단한 테스트를 해 보았습니다.
- 첫번째 테스트 - 373 개의 페이지가 있는 이 곳에서 GyparkWiki 의 역링크를 검색. 5번씩 수행한 평균값
- 현재의 방식 : 4.47 초 (어지간히.. 비효율적인 코딩이긴 했군요. -_-;)
- 1+2 : 0.87 초 (오오..)
- 1+3 : 0.39 초 (오옷!!)
- 두번째 테스트 - 새로운 데이타 디렉토리를 생성하고, UseModWiki소스수정 페이지를 이름을 바꿔가면서 복사함. A 부터 J 까지 10 개 디렉토리에 균등하게 페이지를 나누어 넣음. 페이지 수를 10개(디렉토리당 1개)부터 10000개(디렉토리당 1000개)까지 10배로 늘려가면서 측정
페이지수 | 기존방식 | 1+2방식 | 1+3 방식 |
10 | 0.46 | 0.27 | 0.16 |
100 | 3.96 | 1.473 | 0.29 |
1000 | 39 | 13 | 1 |
10000 | 실험하지않음 | 138 | 34 |
두 실험 다 1+3 방식이 제일 낫다는 것을 보여주고는 있는데.. 두번째 실험은 뭔가 좀 이상하긴 하네요. 기존방식과 1+2 는 페이지수에 정비례하는 쪽으로 나가는 것 같은데... 1+3 방식은 1000 개일 때와 10000 개일 때 30 배로 뛰네요. 제 홈페이지가 있는 서버의 부하 상태에 영향을 받을 수도 있겠고 외부 요인이 많긴 하겠지만.. 어쨌거나 1+3 쪽이 장난이 아니로군요.
그리고, 위의 첫번째 박스에서 maintain 처리하는 부분 좀 이상한데요.. " (delete)" 란 문자열과 message 변수를 비교하고 있는데, 그거 ProcessVetos 패치에서 나온 것 같네요. 그 패치를 적용하지 않을 경우는 불필요한 비교인 듯 합니다. 다른 부분은 그냥 copy & paste 해 넣느라고 뭐 일일이 살펴보지 못했습니다만.. 괜찮겠죠.
음.. 위 실험을 할 때는 서버에 다른 어플 때문에 부하가 많이 걸려 있는 상태였습니다. 어째 요새 홈페이지 뜨는 속도가 좀 느려졌다 싶더니만... 지금 다시 저 테스트를 한다면 조금은 빨라졌겠네요.
또 다른 실험. 거북이님의 홈페이지 koreanrock 의 데이타를 얻어 와서 (감사합니다~) 테스트 해 보았습니다.
- 총 페이지 수 : 2594
- '거북이' 페이지의 역링크 출력 시간 (5번 반복 후 평균)
기존 방식 | 1 + 2 방식 | 1 + 3 방식 | 새로운방식 |
37.7398 | 2.8662 | 1.1334 | 0.6 |
암튼 이리 저리 해도 1+3 방식이 제일 빠른데, 고쳐야 될 게 많다는 점과 (이거야 뭐 복사해 넣으면 되지만) action=link 했을 때도 저 장점을 얻게 하기 위해서는 더 고쳐야겠군요. 적용은 시간을 두고 할 예정입니다. 아니면 이 곳에서는 1+2 방식을 쓰고 1+3 은 별도로 남겨 둘 수도 있고...
- 1+2소스를 쓰실때는 action=link도 속도개선이 될겁니다. allpageto나 orphanedpage매크로같이 action=link관련 함수를 쓰는 매크로들도 한번 테스트 해보세요.
--
Bab2 2003-2-17 4:01 pm
분명히 주인장님께서 고려바위의 페이지를 가지고 테스트를 하셨을거고...저는 지금 가장 최신버젼으로 받아서 올려봤는데 역링크 결과가 안나오네요. 무슨 일일까요...-_- 참고로 소스 만진거 전무합니다...-.-a http://koreanrock.com/wiki_temp.pl --
거북이 2003-2-21 12:54 am
- 아, 아직 UseModWiki소스수정/Download 에 있는 것은 반영되지 않은 것입니다. :-) 아직 테스트가 끝나지 않았습니다.
Bab2님의 소스를 참조하여, 아예 link 목록을 별도의 화일에 나눠서 보관하는 것을 시도중입니다. 겸사겸사, 기존의 action=link 뒤에 붙는 파라메터의 처리도 그대로 호환되게 하고자 합니다. 고려바위 페이지를 가지고 테스트한 바로는 역링크 검색 속도는 참 빠릅니다. 대신 link 를 화일에 저장하는 속도를 조금 희생한 느낌입니다만..
- 굳이 별도의 화일에 나눠서 저장할 필요가 있을까요? 내용도 얼마 안되고 그냥 화일안에 뭉개넣어도 별 상관이 없을것 같다는 생각이 드네요.
- 에.. 그리고...
- 죄송합니다만... -_-;; 저희 홈에서 DoMaintain 접때 북마크가 제대로 표현안되었던게 DoMaintain에서 생각없이 SavePage함수를 불러버린 탓이었습니다(SavePage는 revision을 한개씩 올리더군요.). 어저께 그거때문에 쌩똥을 싸는바람에 ㅜㅡ, 알아서 잘 손보시겠지만, 혹시나 해서 말씀드립니다..ㅜㅡ 일단 지금은 땜빵으로 SavePage를 부르기전에 revision을 한개 낮추도록 해놨습니다. 흑흑.. 맨날 민폐만.. 죄송합니다 ㅜㅡ.
--
Bab2 2003-2-21 12:44 pm
- 민폐는 무슨요, 지금 제가 시도하는 것도 Bab2 님이 이뤄놓은 게 있으니 가능한 거지요. 그리고 다른 화일에 기록을 시도하는 근본적인 이유는... 현재의 방식에서는 링크 목록을 가져오기 위해서 OpenPage 를 하고 있는데, 그냥 역링크 목록만 보는 경우는 상관이 없는데 allpagesto 등과 같이 어떤 페이지 내에서 링크 목록을 가져와야 되는 경우 저 OpenPage 가 다시 불리는 것이 문제가 된다고 판단했습니다. (잘못 생각한 것일수도 있습니다. 페이지 open 과 save 에 관한 부분이 하도 얽히고 �霞淺�...) 그리고, 다른 action 과의 호환성을 위해서 1+2 를 쓰자니, 1+3 에 비해 속도가 떨어지는 게 맘이 아파서, 그렇다면 페이지를 읽는 시간이라도 줄여보자는 것이죠. 나중에 정리되면, Bab2 님의 패치와 같이 정리해서 올리면 사용자가 장단점을 보면서 원하는 코드로 가져가게 하면 될 것 같습니다. 오늘은 하루 종일 컴퓨터 앞에 앉지 못했더니만 어제 어디까지 했는지 기억이 안나는군요. ^^; 좋은 주말 되세요.
- 소스를 보시면 1+2부분에서 for순환문을 두번(맞나 --a)부르는 것을 볼 수 있을 것입니다. 제가 생각하기로는 1+2랑 1+3의 속도차이가 그것 때문에 생기는 것 같고요, 그게 별도의 링크목록을 화일로 저장한다고 해서 특별히 얻는 이득이 없을 것 같단 생각도 들기도 합니다. 캐시같은것들을 고려했을때 OpenPage로 한번 더 열린다고 해도 크게 차이가 나지는 않을거 같습니다. 어차피 한줄(페이지에 속한 링큼목록을 한줄이라 했을때)을 섹션한개로 읽어들인다고 해도 같은 수의 페이지를 읽어들이는 것과 마찬가지일 거니까요. 오늘 친구들이랑 술한잔 했는데 우째야될지 푸념을 늘어놓으니 걍 오렌지랑 딸기장사나 해라고 합니다 -_-;; 내일 아침에 일어나서 맑은정신으로 심호흡한번하고 거북이님한테 메일이나 한통 보내야겠습니다. 양파껍질속에 빈깡통 물러갑니다 :)
--
Bab2 2003-2-22 1:22 am
- 아, OpenPage 의 문제는 속도를 얘기한 것이 아니었습니다. $OpenPageName 과 여러 해쉬변수들이 OpenPage 시에 새롭게 세팅되어 버리는 것이 문제라는 거죠. 이 역링크 패치와 관계없이 옛날부터 문제였던 겁니다만. (예전에 조프님이 이런 비슷한 얘기를 했던 것 같은데 기억이 가물가물..) 어쨌거나 지금 연습장을 보시면... 마지막 편집일이 엉뚱한 시각을 가리키고 있는 걸 볼 수 있습니다. 뭐, 저 부분을 출력하는 곳에서 다시 한 번 OpenPage 를 써서 원래의 페이지 (이 경우는 연습장) 를 불러오도록 하면 해결은 할 수 있겠습니다만... 암튼 특별한 action 이 있는 게 아니라 단지 페이지 하나를 보는 경우에는 OpenPage 가 불리는 것도 최소화하고 싶은 거죠.
- 만고 생각만 했을때, 그것들만 바꾸고자한다면 지역변수(해쉬)로 읽어들이는 함수를 새로 만들던지 아니면 OpenPage로 페이지를 부르는 부분을 GetPageLinks함수에 왕창 넣어주면 될 것 같기도 합니다만... MacroInclude도 그렇게 해버리면 되겠죠. ㅡ.,ㅡa -- bab2
url링크와 inter링크도 따로 저장해서 불릴 수 있게 다시 수정했습니다. 그리고, OpenPage함수를 안쓰려면 그냥
sub GetPageLinks {
....
$fname = &GetPageFile($name);
if (-f $fname) {
$data = &ReadFileOrDie($fname);
%Page = split(/$FS1/, $data, -1);
}
$text = $Page{'links'};
$out_text = $Page{'outlinks'};
....
이렇게 해주면 될 거 같습니다. %Page도 함수 내부에 선언을 해줘야겠죠. 어차피 전역변수와 같은이름이래도 영역은 알아서 구분을 해주니.. 쿨럭~ --
Bab2 2003-2-23 5:27 pm
- 예, 다시 테스트해 보겠습니다. 그리고 관리 메뉴에서 페이지 이름을 바꿨을때나 링크를 변경하는 곳도 손을 봐야겠는데요, 위 패치에서 1+2를 쓴다면
-
sub RenameTextLinks {
...
if ($changed) {
$file = &GetPageFile($page);
$Page{'links'} =~ s/\s원래이름\s/\s바뀔이름\s/g;
&WriteStringToFile($file, join($FS1, %Page));
}
&RenameKeepText($page, $old, $new);
}
}
- 위의 주석 자리에도 링크를 다시 검사하여 넣으면 될 것 같네요. 좀 봐 주시겠어요?
- 저렇게 하던지 귀찮으면 &DoMaintain; 해버려도 되겠네요...으흐흐 ^^;
- 근데 페이지 삭제할때는 lnk화일을 어떻게 처리해주나요?
--
Bab2 2003-2-25 10:57 am
- 페이지 이름 변경만 신경쓰고 있다가.. 삭제를 잊고 있었습니다. -.-a 긁적...
위키위키분류