Liigu peamise sisu juurde

CMake tutvustus Visual Studio abil (lihtsa konsoolirakenduse tegemine)

· Ühe min lugemine
Infokiir OÜ

Esialgu võib üsnagi aega võtta, et aru saada CMake ülesehitusest ja loogikast. Sai sellepärast tehtud väike demo, kuidas alustada Visual Studio CMake projekti. Teeme lihtsa konsooliprogrammi, mis töötab nii Windows-s kui Linux-s. Samuti näeme, kuidas teha teeke ja neid kasutada.

Demo: https://www.youtube.com/watch?v=2_Rd4uqu4-g

Lähtekood: https://github.com/asjadenet/CMakeProjectDemo

Linke:

https://cmake.org/examples/

http://preshing.com/20170522/learn-cmakes-scripting-language-in-15-minutes/

Nipid linkimiseks, ehk kuidas üle saada 'error LNK2019' vigadest

· 3 min lugemine
Infokiir OÜ

Pidin hiljuti maadlema error LNK2019: unresolved external symbol tüüpi vigadega. Põhiliselt tekivad need siis, kui lingitavat lihtsalt ei leita .lib või .obj failidest. Rohkem lugemist selle kohta on siin: https://msdn.microsoft.com/en-us/library/799kze2z.aspx.

Puuduvad .lib või .obj faild saab Visual Studio-s lisada nii:

Project Properties > Configuration Properties > Linker > Input > Additional Dependencies > add

Kuidas aga õiged .lib ja .obj failid üles leida, kui need on eri kohtades laiali? Tegelikult saab selle üsna ruttu tehtud, kui kasutada õiget tööriista.

Alustada võib kiirest ülevaatest. Seda saab ruttu teada käsklusega:

dir *.lib /b /s

või

dir *.obj /b /s

/b vorming näitab failid koos teekonnaga ilma üleliigse infota.

/s otsib kõigist alamkataloogidest rekursiivselt.

Esiteks tasub meeles pidada seda, et välja võib olla jäänud mõni süsteemi teegi fail.

Näiteks sain veateate:

error LNK2001: unresolved external symbol __imp_timeGetTime

Tihtipeale on kõige kiirem lahendus kasutada üldotstarbelist interneti otsingumootorit. Veidi otsides leiame, et tuleks lisada linkimisse teek WinMM.lib. Kui meil pole aimu, kust selle faili võiks leida, siis aitab meid jälle tavaline dir käsklus:

dir WinMM.lib /s

Kuna neid faile võib olla arvutis mitmeid, siis selleks et näha ka faili kuupäeva ja suurust, jätan meelega ära /b võtme.

Kui internetiotsinguga vastust ei leia, tasub kõik oletatavad kataloogid läbi otsida. Mõnevõrra aega nõuab kõigi binaarfailide läbiotsimine, kuid kui meil pole paremat ideed, siis see võibki just meid aidata.

.lib failide läbiotsimiseks tegin käsufaili findlib.bat:

@echo off
echo otsime .lib failidest %1
for /r %%f in (*.lib) do (
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.13.26128\bin\Hostx86\x86\dumpbin.exe" /exports "%%f" | findstr %1
if errorlevel 0 if not errorlevel 1 echo Leitud failist: %%f & echo.
)

Tulemused:

C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10586.0\um\x86>findlib.bat timeGetTime
otsime .lib failidest timeGetTime
_timeGetTime@0
Leitud failist: C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10586.0\um\x86\mmos.lib

_timeGetTime@0
Leitud failist: C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10586.0\um\x86\OneCore.Lib

_timeGetTime@0
Leitud failist: C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10586.0\um\x86\OneCoreUAP.Lib

_timeGetTime@0
Leitud failist: C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10586.0\um\x86\OneCoreUAP_downlevel.Lib

_timeGetTime@0
Leitud failist: C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10586.0\um\x86\OneCore_downlevel.Lib

_timeGetTime@0
Leitud failist: C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10586.0\um\x86\WinMM.Lib

.obj failidest otsimiseks tegin käsufaili:

@echo off
echo otsime .obj failidest %1
for /r %%f in (*.obj) do (
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.13.26128\bin\Hostx86\x86\dumpbin.exe" /SYMBOLS "%%f" | findstr %1
if errorlevel 0 if not errorlevel 1 echo Leitud failist: %%f & echo.
)

Linkimisel on oluline jälgida, et platvorm (x86 või x64) oleks õige.

Samuti on tähtis, et Run-Time Library klapiks kogu rakenduse lõikes.

Selle kohta saab rohkem lugeda siit: https://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx

Tegin väikese MSYS2 bash käsufaili, millega saan teada .lib faili kuupäeva, platvormi ning ka Run-Time Library.

$ cat /usr/bin/libinfo.sh
#! /bin/sh
ls -l $1
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.13.26128\bin\Hostx86\x86\dumpbin.exe" -headers $1 | grep machine | head -n 1
grep -aPo '.{0,20}DEFAULTLIB.{0,12}' $1 | head -n 3

Viiteid: https://msdn.microsoft.com/en-us/library/799kze2z.aspx

https://docs.microsoft.com/en-us/cpp/porting/overview-of-potential-upgrade-issues-visual-cpp

Avatud laiendamisele, suletud muutmisele ehk C++ ja staatiline polümorfism

· 7 min lugemine
Infokiir OÜ

Kui sissejuhatuseks rääkida veidi raamatutest, siis Robert C. Martin-i sulest ilmunud teos "Agile Principles, Patterns, and Practices in C#" on klassika, mis ilmselt tasub küll igal programmeerijal läbi lugeda. Siin tutvustatud niinimetatud SOLID printsiibid on väärt rakendamist, kuigi alati ei õnnestu see tavaliselt 100%-liselt.

Võtame korraks vaatluse alla "Avatud laiendamisele, suletud muutmisele" põhimõtte, millega on tihedalt seotud ka SRP.

Meenus ammune juuni 2008 MSDN-s ilmunud Jeremy Miller kirjutatud artikkel "The Open Closed Principle". Seal on kasutusel muidugi dünaamiline polümorfism. Kuid C++ võimaldab ka staatilist polümorfismi ilma VTABLE-t kasutamata. Eriti meeldib see mikrokontrollerite programmeerijatele, sest see võimaldab tihtipeale mälu kokku hoida ja töötab ka kiiremini.

Alustame lihtsa näitega, kus kasutame tavalist if-else hargnemist. Me ei järgi siin erilisi printsiipe, kasutame lihtsalt niiöelda oma talupojamõistust:

#include <iostream>

enum class OrderType {
Domestic, International
};

struct Order {
int order_id;
int customer_id;
OrderType orderType;
};

struct SelectAndProcess {
static void execute(Order &order) {
if(order.orderType == OrderType::International)
{
std::cout << "Processing InternationalOrder id:" << order.order_id << '\n';
}
else if (order.orderType == OrderType::Domestic) {
std::cout << "Processing DomesticOrder id:" << order.order_id << '\n';
}
}
};

int main() {
Order domestic{1, 1, OrderType::Domestic};
Order international{2, 3, OrderType::International};
Order domestic2{3, 4, OrderType::Domestic};
SelectAndProcess::execute(domestic);
SelectAndProcess::execute(international);
SelectAndProcess::execute(domestic2);
return 0;
}

Lihtsuse mõttes on kõik struktuurid ja klassid samas failis. Need saaks küll paigutada erinevatesse failidesse, kuid me ei keskendu praegu sellele.

Seda koodi võib vaadata aadressilt: https://godbolt.org/g/GgNsJA. Assembleris on siin 74 rida.

Ülaltoodud kood on ilmselt esimene viis, kuidas me programmeerijatena oleme alustanud. Suureks plussiks on siin lihtsus. Koodi ei ole ka palju ja see on praegu lihtsasti arusaadav. Programm väljastab:

Processing DomesticOrder id:1
Processing InternationalOrder id:2
Processing DomesticOrder id:3

Kogenud programmeerija näeb siin siiski probleeme:

  • struct SelectAndProcess on reaalses elus kindlasti palju keerulisem. Mõistlik oleks, et iga if lause taga olev kood oleks omaette funktsioonis või pigem klassis. Võime ette kujutada (kindlasti oleme ise näinud või ka ise kirjutanud), kui pikaks see execute meetod võib minna.
  • Kui soovime näiteks lisada uue Order tüübi Special, siis peaksime lisame veel ühe if lause ning meie execute meetod venib veelgi pikemaks. Kuidas oleks tulevikus sellist koodi hooldada? See ei ole väga tore. Vigu võib kergesti tulla ja see võib olla aeganõudev.
  • See kood ei vasta ei SRP ega ka OCP põhimõttele.

Järgmisena vaatame kuidas lahendada sama ülesanne dünaamilise polümorfismi abil, kasutades abstraktset baasklassi. Sisuliselt peame muutma vaid SelectAndProcess avalikku klassi.

#include <iostream>

enum class OrderType {
Domestic, International
};

struct Order {
int order_id;
int customer_id;
OrderType orderType;
};

struct OrderHandler {
virtual ~OrderHandler() {}

virtual void process_order(Order &order)= 0;

virtual bool can_process(Order &order)= 0;
};

struct DomesticOrderProcessor : OrderHandler {
void process_order(Order &order) override {
std::cout << "Processing DomesticOrder id:" << order.order_id << '\n';
}

bool can_process(Order &order) override {
return (order.orderType == OrderType::Domestic);
}
};

struct InternationalOrderProcessor : OrderHandler {
void process_order(Order &order) override {
std::cout << "Processing InternationalOrder id:" << order.order_id << '\n';
}

bool can_process(Order &order) override {
return (order.orderType == OrderType::International);
}
};


struct SelectAndProcess {
static void execute(Order &order) {
DomesticOrderProcessor domesticOrderProcessor;
InternationalOrderProcessor internationalOrderProcessor;
OrderHandler *arr[] = {&domesticOrderProcessor, &internationalOrderProcessor};
int size = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < size; ++i) {
if (arr[i]->can_process(order)) {
arr[i]->process_order(order);
return;
}
}
}
};

int main() {
Order domestic{1, 1, OrderType::Domestic};
Order international{2, 3, OrderType::International};
Order domestic2{3, 4, OrderType::Domestic};
SelectAndProcess::execute(domestic);
SelectAndProcess::execute(international);
SelectAndProcess::execute(domestic2);
return 0;
}

Käivitame selle ja tulemus on sama:

Processing DomesticOrder id:1
Processing InternationalOrder id:2
Processing DomesticOrder id:3

Assembleris on ridu gcc-ga kõvasti rohkem: https://godbolt.org/g/itBHRg. Siin on näha ka, et genereeriti vastavad vtable read.

Kui vaadata clang abil genereeritud listingut https://godbolt.org/g/jwHW3r, siis on ridu kõvasti vähem ja ka vtable read puuduvad.

Nüüd siis sama asi staatilist polümorfismi kasutades. Ilma template võimalust kasutades näeb kood välja niimoodi:

#include <iostream>

enum class OrderType {
Domestic, International
};

struct Order {
int order_id;
int customer_id;
OrderType orderType;
};

struct DomesticOrderProcessor {
bool process(Order &order)
{
if (order.orderType == OrderType::Domestic) {
std::cout << "Processing DomesticOrder id:" << order.order_id << '\n';
return true;
}
return false;
}
};

struct InternationalOrderProcessor {
bool process(Order &order) {
if (order.orderType == OrderType::International) {
std::cout << "Processing InternationalOrder id:" << order.order_id << '\n';
return true;
}
return false;
}
};

inline int process_order(InternationalOrderProcessor &orderp, Order &order) {
return orderp.process(order);
}

inline int process_order(DomesticOrderProcessor &orderp, Order &order) {
return orderp.process(order);
}

struct SelectAndProcess {
static int execute(Order &order) {
DomesticOrderProcessor domestic_order;
InternationalOrderProcessor international_order;
if (process_order(domestic_order, order)) return 0;
process_order(international_order, order);
return 0;
}
};

int main() {
Order domestic{1, 1, OrderType::Domestic};
Order international{2, 3, OrderType::International};
Order domestic2{3, 4, OrderType::Domestic};
SelectAndProcess::execute(domestic);
SelectAndProcess::execute(international);
SelectAndProcess::execute(domestic2);
return 0;
}

Assembleri listingus saime 78 koodirida: https://godbolt.org/g/j8PBxU

Kasutasime siin ära selle, et vastavalt meetodi parameetritele käivitatakse ka vastav funktsioon. Järgmisena võtame appi C++ template, mis võimaldab meil koodi mitte korrata:

template<typename order_processor>
int process_order(order_processor &orderp, Order &order) {
return orderp.process(order);
}

kogu programm:

#include <iostream>

enum class OrderType {
Domestic, International
};

struct Order {
int order_id;
int customer_id;
OrderType orderType;
};

struct DomesticOrderProcessor {
bool process(Order &order)
{
if (order.orderType == OrderType::Domestic) {
std::cout << "Processing DomesticOrder id:" << order.order_id << '\n';
return true;
}
return false;
}
};

struct InternationalOrderProcessor {
bool process(Order &order) {
if (order.orderType == OrderType::International) {
std::cout << "Processing InternationalOrder id:" << order.order_id << '\n';
return true;
}
return false;
}
};

template<typename order_processor>
int process_order(order_processor &orderp, Order &order) {
return orderp.process(order);
}

struct SelectAndProcess {
static int execute(Order &order) {
DomesticOrderProcessor domestic_order;
InternationalOrderProcessor international_order;
if (process_order(domestic_order, order)) return 0;
process_order(international_order, order);
return 0;
}
};

int main() {
Order domestic{1, 1, OrderType::Domestic};
Order international{2, 3, OrderType::International};
Order domestic2{3, 4, OrderType::Domestic};
SelectAndProcess::execute(domestic);
SelectAndProcess::execute(international);
SelectAndProcess::execute(domestic2);
return 0;
}

Assembleri listing https://godbolt.org/g/Qf3F9F on tegelikult täpselt sama.

Lõpuks veel sama asi CRTP abil:

#include <iostream>

enum class OrderType {
Domestic, International
};

struct Order {
int order_id;
int customer_id;
OrderType orderType;
};

template<class Derived>
struct base {
void process() {
static_cast<Derived *>(this)->process();
};
};

struct DomesticOrderProcessor : base<DomesticOrderProcessor> {
bool process(Order &order) {
if (order.orderType == OrderType::Domestic) {
std::cout << "Processing DomesticOrder id:" << order.order_id << '\n';
return true;
}
return false;
}
};

struct InternationalOrderProcessor : base<InternationalOrderProcessor> {
bool process(Order &order) {
if (order.orderType == OrderType::International) {
std::cout << "Processing InternationalOrder id:" << order.order_id << '\n';
return true;
}
return false;
}
};

template<typename order_processor>
int process_order(order_processor &orderp, Order &order) {
return orderp.process(order);
}

struct SelectAndProcess {
static int execute(Order &order) {
DomesticOrderProcessor domestic_order;
InternationalOrderProcessor international_order;
if (process_order(domestic_order, order)) return 0;
process_order(international_order, order);
return 0;
}
};

int main() {
Order domestic{1, 1, OrderType::Domestic};
Order international{2, 3, OrderType::International};
Order domestic2{3, 4, OrderType::Domestic};
SelectAndProcess::execute(domestic);
SelectAndProcess::execute(international);
SelectAndProcess::execute(domestic2);
return 0;
}

Genereeritud assembleri listing on ikka sama: https://godbolt.org/g/e4s5iF. Koodi tuli juurde, aga olulist võitu sellest ei tulnud.

Mida öelda kokkuvõtteks?

  • On hea teada nii dünaamilise kui staatilise polümorfismi võimalusi. See aitab kirjutada kergemini hallatavad koodi.
  • Tasub vaadata ja võrrelda genereeritud assembleri listinguid. Optimeeritud kompilaator võib meid üllatada. Näiteks clang-i genereeritud dünaamilise polümorfismiga variant ei sisaldanudki vtable ridu.

linke:

https://www.safaribooksonline.com/library/view/agile-principles-patterns/0131857258/

https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)

https://en.wikipedia.org/wiki/Open/closed_principle

https://en.wikipedia.org/wiki/Single_responsibility_principle

https://blogs.msdn.microsoft.com/msdnmagazine/2008/07/02/patterns-in-practice-the-open-closed-principle/

http://download.microsoft.com/download/3/a/7/3a7fa450-1f33-41f7-9e6d-3aa95b5a6aea/MSDNMagazine2008_06en-us.chm

https://en.wikipedia.org/wiki/Template_metaprogramming#Static_polymorphism

Real-Time C++ http://www.springer.com/gp/book/9783662478097

Enda otsingumootor ehk kuidas otsida infot staatiliselt veebisaidilt (Apache Solr ja Nutch)

· 6 min lugemine
Infokiir OÜ

Staatilisel veebisaidil on omad eelised: see on lihtsam, kiirem ja turvalisem kui dünaamiline sait. Nii nagu staatilist veebisaiti tehes, võib koostada ka dokumendikogu, kasutades markdown süntaksit.

Kuidas aga korraldada otsing, kui soovime dokumente hoida vaid sisevõrgus? Keegi ei keela enda otsingumootori püstipanekut. Toon siin lihtsa näite, kuidas seda teha Apache Solr ja Apache Nutch abil. Siintoodud juhend on Linux keskkonnas, kuid see töötab ka näiteks WSL keskkonnas.

Internetis on üsna hea lihtne juhend: https://factorpad.com/tech/solr/tutorial/solr-web-crawl.html. Ainuke häda on see, et veebisaidi sisu allalaadides -recursive võtmega kipub ilmuma veateade "[Fatal Error] :1:1: Content is not allowed in prolog." Selleks, et sellest üle saada, kasutame Apache Nutch-i.

Kuna lihtsasti mõistetavat ja töötavat õpetust oli raske leida, panen siis selle nüüd kirja.

tiit@tiit-Virtual-Machine:~$ cd
tiit@tiit-Virtual-Machine:~$ mkdir solr
tiit@tiit-Virtual-Machine:~$ cd solr
tiit@tiit-Virtual-Machine:~/solr$ wget http://www-us.apache.org/dist/lucene/solr/7.2.0/solr-7.2.0.tgz
tiit@tiit-Virtual-Machine:~/solr$ tar xf solr-7.2.0.tgz
tiit@tiit-Virtual-Machine:~/solr$ cd solr-7.2.0/
tiit@tiit-Virtual-Machine:~/solr/solr-7.2.0$ bin/solr start
tiit@tiit-Virtual-Machine:~/solr/solr-7.2.0$ bin/solr create_core -c infokiir
WARNING: Using _default configset. Data driven schema functionality is enabled by default, which is
NOT RECOMMENDED for production use.

To turn it off:
curl http://localhost:8983/solr/infokiir/config -d '{"set-user-property": {"update.autoCreateFields":"false"}}'

Created new core 'infokiir'
tiit@tiit-Virtual-Machine:~/solr/solr-7.2.0$

Veendume ka, et meil oleks java installeeritud:

tiit@tiit-Virtual-Machine:~/solr/solr-7.2.0$ java -version
openjdk version "1.8.0_151"
OpenJDK Runtime Environment (build 1.8.0_151-8u151-b12-0ubuntu0.16.04.2-b12)
OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode)

Juhul, kui JAVA_HOME ei ole väärtustatud, siis teen seda käsklusega:

export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64

Edasi:

tiit@tiit-Virtual-Machine:~/solr/solr-7.2.0$ cd
tiit@tiit-Virtual-Machine:~$ mkdir nutch
tiit@tiit-Virtual-Machine:~$ cd nutch/
tiit@tiit-Virtual-Machine:~/nutch$ wget http://www-eu.apache.org/dist/nutch/1.14/apache-nutch-1.14-bin.tar.gz
--2018-01-08 14:04:20-- http://www-eu.apache.org/dist/nutch/1.14/apache-nutch-1.14-bin.tar.gz
Lahendan www-eu.apache.org (www-eu.apache.org)... 195.154.151.36, 2001:bc8:2142:300::
Loon ühendust serveriga www-eu.apache.org (www-eu.apache.org)|195.154.151.36|:80... ühendus loodud.
HTTP päring saadetud, ootan vastust... 200 OK
Pikkus: 249107211 (238M) [application/x-gzip]
Salvestan: `apache-nutch-1.14-bin.tar.gz'

apache-nutch-1.14-bin.tar.gz 100%[=============================================================================================>] 237,57M 5,30MB/s in 48s

2018-01-08 14:05:09 (4,93 MB/s) - `apache-nutch-1.14-bin.tar.gz' salvestatud [249107211/249107211]

tiit@tiit-Virtual-Machine:~/nutch$ tar xf apache-nutch-1.14-bin.tar.gz
tiit@tiit-Virtual-Machine:~/nutch$ cd apache-nutch-1.14/

Proovin, kas crawl käivitub:

tiit@tiit-Virtual-Machine:~/nutch/apache-nutch-1.14$ bin/crawl
Usage: crawl [-i|--index] [-D "key=value"] [-w|--wait] [-s <Seed Dir>] <Crawl Dir> <Num Rounds>
-i|--index Indexes crawl results into a configured indexer
-D A Java property to pass to Nutch calls
-w|--wait NUMBER[SUFFIX] Time to wait before generating a new segment when no URLs
are scheduled for fetching. Suffix can be: s for second,
m for minute, h for hour and d for day. If no suffix is
specified second is used by default.
-s Seed Dir Path to seeds file(s)
Crawl Dir Directory where the crawl/link/segments dirs are saved
Num Rounds The number of rounds to run this crawl for
tiit@tiit-Virtual-Machine:~/nutch/apache-nutch-1.14$

Edasi seadistame mõned parameetrid:

tiit@tiit-Virtual-Machine:~/nutch/apache-nutch-1.14$ nano conf/nutch-site.xml

Kopeerin "configuration" tag-de vahele (sisu laenatud veebisaidilt http://opensourceconnections.com/blog/2014/05/24/crawling-with-nutch/):

<property>
<name>http.agent.name</name>
<value>MyBot</value>
<description>MUST NOT be empty. The advertised version will have Nutch appended.</description>
</property>
<property>
<name>http.robots.agents</name>
<value>MyBot,*</value>
<description>The agent strings we'll look for in robots.txt files,
comma-separated, in decreasing order of precedence. You should
put the value of http.agent.name as the first agent name, and keep the
default * at the end of the list. E.g.: BlurflDev,Blurfl,*. If you don't, your logfile will be full of warnings.
</description>
</property>
<property>
<name>fetcher.store.content</name>
<value>true</value>
<description>If true, fetcher will store content. Helpful on the getting-started stage, as you can recover failed steps, but may cause performance problems on larger crawls.</description>
</property>

<property>
<name>fetcher.max.crawl.delay</name>
<value>-1</value>
<description>
If the Crawl-Delay in robots.txt is set to greater than this value (in
seconds) then the fetcher will skip this page, generating an error report. If set to -1 the fetcher will never skip such pages and will wait the amount of time retrieved from robots.txt Crawl-Delay, however long that might be.
</description>
</property>

<!-- Applicable plugins-->
<property>
<name>plugin.includes</name>
<value>protocol-http|urlfilter-regex|parse-(html|tika|metatags)|index-(basic|anchor|metadata)|query-(basic|site|url)|response-(json|xml)|summary-basic|scoring-opic|indexer-solr|urlnormalizer-(pass|regex|basic)</value>
<description> At the very least, I needed to add the parse-html, urlfilter-regex, and the indexer-solr.
</description>
</property>
```![](2018-01-08-14-54-15.png)

```bash
tiit@tiit-Virtual-Machine:~/nutch/apache-nutch-1.14$ nano urls/seed.text

Lisan siia rea:

http://www.infokiir.ee

Kommenteerin välja viimase rea ja lisan:

#+.
+^https?://([a-z0-9-]+\.)*www\.infokiir\.ee/

See on vajalik selleks, et me püsiks www.infokiir.ee veebisaidil ega hakkaks alla laadima väliseid viidatud veebisaite.

Veebisaidi sisu allalaadimine käib kahes etapis. Kõigepealt käivitan:

tiit@tiit-Virtual-Machine:~/nutch/apache-nutch-1.14$ bin/crawl -s urls crawl/ 2

Seejärel:

tiit@tiit-Virtual-Machine:~/nutch/apache-nutch-1.14$ bin/nutch solrindex http://localhost:8983/solr/infokiir crawl/crawldb/ crawl/segments/*
Segment dir is complete: crawl/segments/20180108144502.
Segment dir is complete: crawl/segments/20180108144521.
Indexer: starting at 2018-01-08 14:48:13
Indexer: deleting gone documents: false
Indexer: URL filtering: false
Indexer: URL normalizing: false
Active IndexWriters :
SOLRIndexWriter
solr.server.url : URL of the SOLR instance
solr.zookeeper.hosts : URL of the Zookeeper quorum
solr.commit.size : buffer size when sending to SOLR (default 1000)
solr.mapping.file : name of the mapping file for fields (default solrindex-mapping.xml)
solr.auth : use authentication (default false)
solr.auth.username : username for authentication
solr.auth.password : password for authentication


Indexing 6/6 documents
Deleting 0 documents
Indexer: number of documents indexed, deleted, or skipped:
Indexer: 6 indexed (add/update)
Indexer: finished at 2018-01-08 14:48:16, elapsed: 00:00:02
tiit@tiit-Virtual-Machine:~/nutch/apache-nutch-1.14$

Nüüd vaatan tulemust:

Otsing:

Linke:

https://et.wikipedia.org/wiki/Markdown

https://lucene.apache.org/solr/

http://nutch.apache.org/

https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux

https://factorpad.com/tech/solr/tutorial/solr-web-crawl.html

http://opensourceconnections.com/blog/2014/05/24/crawling-with-nutch/

https://lobster1234.github.io/2017/08/14/search-with-nutch-mongodb-solr/