triannon 1.1.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +64 -48
- data/app/controllers/concerns/rdf_response_formats.rb +7 -11
- data/app/controllers/triannon/annotations_controller.rb +34 -24
- data/app/models/triannon/annotation.rb +13 -16
- data/app/services/triannon/ldp_loader.rb +13 -34
- data/app/services/triannon/ldp_to_oa_mapper.rb +19 -13
- data/app/services/triannon/ldp_writer.rb +49 -46
- data/app/services/triannon/solr_searcher.rb +8 -6
- data/app/services/triannon/solr_writer.rb +11 -6
- data/app/views/triannon/annotations/new.html.erb +21 -1
- data/app/views/triannon/annotations/show.html.erb +1 -1
- data/config/routes.rb +73 -22
- data/config/solr/log4j.properties +25 -0
- data/config/solr/solr.xml +2 -0
- data/config/solr/triannon-core/conf/schema.xml +2 -0
- data/config/solr/triannon-core/conf/solrconfig.xml +46 -33
- data/lib/tasks/triannon_tasks.rake +30 -8
- data/lib/triannon.rb +0 -1
- data/lib/triannon/error.rb +14 -0
- data/lib/triannon/version.rb +1 -1
- metadata +3 -18
- data/app/views/triannon/annotations/_form.html.erb +0 -21
- data/app/views/triannon/annotations/edit.html.erb +0 -1
data/config/routes.rb
CHANGED
@@ -1,31 +1,82 @@
|
|
1
1
|
Triannon::Engine.routes.draw do
|
2
2
|
|
3
|
-
|
4
|
-
# show action must explicitly forbid "new", "iiif" and "oa" as id values; couldn't
|
5
|
-
# figure out how to do it with regexp constraint since beginning and end regex
|
6
|
-
# matchers aren't allowed when enforcing formats for segment (e.g. :id)
|
7
|
-
constraints: lambda { |request|
|
8
|
-
id = request.env["action_dispatch.request.path_parameters"][:id]
|
9
|
-
id !~ /^iiif$/ && id !~ /^oa$/ && id !~ /^search$/
|
10
|
-
} do
|
11
|
-
collection do
|
12
|
-
get 'search', to: 'search#find'
|
13
|
-
end
|
14
|
-
end
|
3
|
+
# 1. can't use resourceful routing because of :anno_root (dynamic path segment)
|
15
4
|
|
5
|
+
# 2. couldn't figure out how to exclude specific values with regexp constraint since beginning and end regex matchers
|
6
|
+
# aren't allowed when enforcing formats for path segment (i.e. :anno_root, :id)
|
7
|
+
|
8
|
+
# get -> new action
|
9
|
+
get '/annotations/:anno_root/new', to: 'annotations#new'
|
10
|
+
get '/:anno_root/new', to: 'annotations#new',
|
11
|
+
constraints: lambda { |request|
|
12
|
+
anno_root = request.path_parameters[:anno_root]
|
13
|
+
id = request.path_parameters[:id]
|
14
|
+
anno_root !~ /^annotations$/ && anno_root !~ /^search$/ && anno_root !~ /^new$/ && id !~ /^search$/ && id !~ /^new$/
|
15
|
+
}
|
16
|
+
|
17
|
+
# get -> search controller find action
|
18
|
+
get '/annotations/:anno_root/search', to: 'search#find'
|
19
|
+
get '/annotations/search', to: 'search#find'
|
20
|
+
get '/:anno_root/search', to: 'search#find',
|
21
|
+
constraints: lambda { |request|
|
22
|
+
anno_root = request.path_parameters[:anno_root]
|
23
|
+
anno_root !~ /^annotations$/ && anno_root !~ /^search$/ && anno_root !~ /^new$/
|
24
|
+
}
|
16
25
|
get '/search', to: 'search#find'
|
17
26
|
|
18
|
-
|
27
|
+
# get w id -> show action
|
28
|
+
get '/annotations/:anno_root/:id(.:format)', to: 'annotations#show',
|
29
|
+
constraints: lambda { |request|
|
30
|
+
anno_root = request.path_parameters[:anno_root]
|
31
|
+
anno_root !~ /^search$/ && anno_root !~ /^new$/
|
32
|
+
}
|
33
|
+
get '/:anno_root/:id(.:format)', to: 'annotations#show',
|
34
|
+
constraints: lambda { |request|
|
35
|
+
anno_root = request.path_parameters[:anno_root]
|
36
|
+
id = request.path_parameters[:id]
|
37
|
+
anno_root !~ /^annotations$/ && anno_root !~ /^search$/ && anno_root !~ /^new$/ && id !~ /^search$/ && id !~ /^new$/
|
38
|
+
}
|
19
39
|
|
20
|
-
#
|
21
|
-
|
22
|
-
# out how to do it with regexp constraint since beginning and end regex
|
23
|
-
# matchers aren't allowed when enforcing formats for segment (e.g. :id)
|
24
|
-
get '/annotations/:jsonld_context/:id(.:format)', to: 'annotations#show',
|
40
|
+
# get no id -> index action
|
41
|
+
get '/annotations/:anno_root', to: 'annotations#index',
|
25
42
|
constraints: lambda { |request|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
43
|
+
anno_root = request.path_parameters[:anno_root]
|
44
|
+
anno_root !~ /^search$/ && anno_root !~ /^new$/
|
45
|
+
}
|
46
|
+
get '/:anno_root', to: 'annotations#index',
|
47
|
+
constraints: lambda { |request|
|
48
|
+
anno_root = request.path_parameters[:anno_root]
|
49
|
+
anno_root !~ /^annotations$/ && anno_root !~ /^search$/ && anno_root !~ /^new$/
|
50
|
+
}
|
51
|
+
|
52
|
+
# post -> create action
|
53
|
+
post '/annotations/:anno_root', to: 'annotations#create',
|
54
|
+
constraints: lambda { |request|
|
55
|
+
anno_root = request.path_parameters[:anno_root]
|
56
|
+
id = request.path_parameters[:id]
|
57
|
+
anno_root !~ /^search$/ && anno_root !~ /^new$/ && id !~ /^search$/ && id !~ /^new$/
|
58
|
+
}
|
59
|
+
post '/:anno_root', to: 'annotations#create',
|
60
|
+
constraints: lambda { |request|
|
61
|
+
anno_root = request.path_parameters[:anno_root]
|
62
|
+
anno_root !~ /^annotations$/ && anno_root !~ /^search$/ && anno_root !~ /^new$/
|
63
|
+
}
|
64
|
+
|
65
|
+
# delete -> destroy action
|
66
|
+
delete '/annotations/:anno_root/:id(.:format)', to: 'annotations#destroy',
|
67
|
+
constraints: lambda { |request|
|
68
|
+
anno_root = request.path_parameters[:anno_root]
|
69
|
+
id = request.path_parameters[:id]
|
70
|
+
anno_root !~ /^search$/ && anno_root !~ /^new$/ && id !~ /^search$/ && id !~ /^new$/
|
71
|
+
}
|
72
|
+
delete '/:anno_root/:id(.:format)', to: 'annotations#destroy',
|
73
|
+
constraints: lambda { |request|
|
74
|
+
anno_root = request.path_parameters[:anno_root]
|
75
|
+
anno_root !~ /^annotations$/ && anno_root !~ /^search$/ && anno_root !~ /^new$/
|
76
|
+
}
|
77
|
+
|
78
|
+
|
79
|
+
get '/annotations', to: 'search#find'
|
80
|
+
root to: 'search#find'
|
30
81
|
|
31
82
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# Logging level
|
2
|
+
solr.log=logs/
|
3
|
+
log4j.rootLogger=INFO, file, CONSOLE
|
4
|
+
|
5
|
+
# Log warnings to the console
|
6
|
+
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
|
7
|
+
log4j.appender.CONSOLE.Threshold=WARN
|
8
|
+
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
|
9
|
+
log4j.appender.CONSOLE.layout.ConversionPattern=%-4r [%t] %-5p %c %x \u2013 %m%n
|
10
|
+
|
11
|
+
#- size rotation with log cleanup.
|
12
|
+
log4j.appender.file=org.apache.log4j.RollingFileAppender
|
13
|
+
log4j.appender.file.MaxFileSize=4MB
|
14
|
+
log4j.appender.file.MaxBackupIndex=9
|
15
|
+
|
16
|
+
#- File to log to and log format
|
17
|
+
log4j.appender.file.File=${solr.log}/solr.log
|
18
|
+
log4j.appender.file.layout=org.apache.log4j.PatternLayout
|
19
|
+
log4j.appender.file.layout.ConversionPattern=%-5p - %d{yyyy-MM-dd HH:mm:ss.SSS}; %C; %m\n
|
20
|
+
|
21
|
+
log4j.logger.org.apache.zookeeper=WARN
|
22
|
+
log4j.logger.org.apache.hadoop=WARN
|
23
|
+
|
24
|
+
# set to INFO to enable infostream log messages
|
25
|
+
log4j.logger.org.apache.solr.update.LoggingInfoStream=OFF
|
data/config/solr/solr.xml
CHANGED
@@ -29,8 +29,10 @@
|
|
29
29
|
If 'null' (or absent), cores will not be manageable via REST
|
30
30
|
-->
|
31
31
|
<cores adminPath="/admin/cores" defaultCoreName="development">
|
32
|
+
<!-- don't need development or test cores for triannon
|
32
33
|
<core name="development" instanceDir="development-core" />
|
33
34
|
<core name="test" instanceDir="test-core" />
|
35
|
+
-->
|
34
36
|
<core name="triannon" instanceDir="triannon-core" />
|
35
37
|
</cores>
|
36
38
|
</solr>
|
@@ -10,6 +10,8 @@
|
|
10
10
|
<field name="id" type="string" stored="true" indexed="true" multiValued="false" required="true"/>
|
11
11
|
<field name="timestamp" type="date" stored="true" indexed="true" multiValued="false" default="NOW"/>
|
12
12
|
|
13
|
+
<field name="root" type="string" stored="true" indexed="true" multiValued="false"/>
|
14
|
+
|
13
15
|
<field name="motivation" type="string" stored="true" indexed="true" multiValued="true"/>
|
14
16
|
<!-- date field format: 1995-12-31T23:59:59Z; or w fractional seconds: 1995-12-31T23:59:59.999Z -->
|
15
17
|
<field name="annotated_at" type="date" stored="true" indexed="true" multiValued="false"/>
|
@@ -4,11 +4,15 @@
|
|
4
4
|
this file, see http://wiki.apache.org/solr/SolrConfigXml.
|
5
5
|
-->
|
6
6
|
<config>
|
7
|
-
<luceneMatchVersion>4.
|
7
|
+
<luceneMatchVersion>4.10.4</luceneMatchVersion>
|
8
|
+
|
9
|
+
<!-- solr lib dirs -->
|
10
|
+
<lib dir="../lib/contrib/analysis-extras/lib" />
|
11
|
+
<lib dir="../lib/contrib/analysis-extras/lucene-libs" />
|
8
12
|
|
9
13
|
<dataDir>${solr.data.dir:}</dataDir>
|
10
14
|
|
11
|
-
<directoryFactory name="DirectoryFactory" class="${solr.directoryFactory:solr.
|
15
|
+
<directoryFactory name="DirectoryFactory" class="${solr.directoryFactory:solr.StandardDirectoryFactory}"/>
|
12
16
|
<codecFactory class="solr.SchemaCodecFactory"/>
|
13
17
|
<schemaFactory class="ClassicIndexSchemaFactory"/>
|
14
18
|
|
@@ -24,7 +28,7 @@
|
|
24
28
|
<str name="dir">${solr.data.dir:}</str>
|
25
29
|
</updateLog>
|
26
30
|
<autoCommit>
|
27
|
-
<maxTime>
|
31
|
+
<maxTime>3000</maxTime>
|
28
32
|
<openSearcher>false</openSearcher>
|
29
33
|
</autoCommit>
|
30
34
|
</updateHandler>
|
@@ -42,21 +46,23 @@
|
|
42
46
|
It should only have the most common facets -->
|
43
47
|
<listener event="newSearcher" class="solr.QuerySenderListener">
|
44
48
|
<arr name="queries">
|
45
|
-
|
49
|
+
<lst>
|
46
50
|
<!-- default query for all objects: populate facet caches -->
|
47
51
|
<int name="rows">0</int>
|
48
52
|
<str name="fl">score</str>
|
49
53
|
<bool name="facet">true</bool>
|
50
54
|
<int name="facet.mincount">1</int>
|
55
|
+
<str name="facet.field">root</str>
|
56
|
+
<str name="f.root.facet.method">enum</str>
|
51
57
|
<str name="facet.field">motivation</str>
|
52
|
-
|
58
|
+
<str name="f.motivation.facet.method">enum</str>
|
53
59
|
<str name="facet.field">target_type</str>
|
54
60
|
<str name="f.target_type.facet.method">enum</str>
|
55
61
|
<str name="facet.field">body_type</str>
|
56
62
|
<str name="f.body_type.facet.method">enum</str>
|
57
63
|
<str name="facet.field">annotated_at_tdate</str>
|
58
64
|
</lst>
|
59
|
-
|
65
|
+
<lst>
|
60
66
|
<!-- single object query: populate filter and fieldValue caches -->
|
61
67
|
<str name="q">id:a*</str>
|
62
68
|
<str name="defType">lucene</str>
|
@@ -64,11 +70,13 @@
|
|
64
70
|
<str name="fl">score</str>
|
65
71
|
<bool name="facet">true</bool>
|
66
72
|
<int name="facet.mincount">1</int>
|
73
|
+
<str name="facet.field">root</str>
|
74
|
+
<str name="f.root.facet.method">enum</str>
|
67
75
|
<str name="facet.field">motivation</str>
|
68
76
|
<str name="f.motivation.facet.method">enum</str>
|
69
77
|
<str name="facet.field">target_type</str>
|
70
78
|
<str name="f.target_type.facet.method">enum</str>
|
71
|
-
|
79
|
+
<str name="facet.field">body_type</str>
|
72
80
|
<str name="f.body_type.facet.method">enum</str>
|
73
81
|
<str name="facet.field">annotated_at_tdate</str>
|
74
82
|
</lst>
|
@@ -78,20 +86,22 @@
|
|
78
86
|
<!-- A First Searcher is opened when there is _no_ existing (current) Searcher. ("fast warmup") -->
|
79
87
|
<listener event="firstSearcher" class="solr.QuerySenderListener">
|
80
88
|
<arr name="queries">
|
81
|
-
|
89
|
+
<lst>
|
82
90
|
<!-- default query for all objects: populate facet caches -->
|
83
91
|
<int name="rows">0</int>
|
84
92
|
<str name="fl">score</str>
|
85
93
|
<bool name="facet">true</bool>
|
86
94
|
<int name="facet.mincount">1</int>
|
95
|
+
<str name="facet.field">root</str>
|
96
|
+
<str name="f.root.facet.method">enum</str>
|
87
97
|
<str name="facet.field">motivation</str>
|
88
98
|
<str name="f.motivation.facet.method">enum</str>
|
89
99
|
<str name="facet.field">target_type</str>
|
90
100
|
<str name="f.target_type.facet.method">enum</str>
|
91
|
-
|
101
|
+
<str name="facet.field">body_type</str>
|
92
102
|
<str name="f.body_type.facet.method">enum</str>
|
93
103
|
</lst>
|
94
|
-
|
104
|
+
<lst>
|
95
105
|
<!-- single object query: populate filter and fieldValue caches -->
|
96
106
|
<str name="q">id:a*</str>
|
97
107
|
<str name="defType">lucene</str>
|
@@ -99,11 +109,13 @@
|
|
99
109
|
<str name="fl">score</str>
|
100
110
|
<bool name="facet">true</bool>
|
101
111
|
<int name="facet.mincount">1</int>
|
112
|
+
<str name="facet.field">root</str>
|
113
|
+
<str name="f.root.facet.method">enum</str>
|
102
114
|
<str name="facet.field">motivation</str>
|
103
115
|
<str name="f.motivation.facet.method">enum</str>
|
104
116
|
<str name="facet.field">target_type</str>
|
105
117
|
<str name="f.target_type.facet.method">enum</str>
|
106
|
-
|
118
|
+
<str name="facet.field">body_type</str>
|
107
119
|
<str name="f.body_type.facet.method">enum</str>
|
108
120
|
</lst>
|
109
121
|
</arr>
|
@@ -123,9 +135,9 @@
|
|
123
135
|
<requestHandler name="/select" class="solr.SearchHandler" default="true">
|
124
136
|
<lst name="defaults">
|
125
137
|
<str name="echoParams">explicit</str>
|
126
|
-
|
127
|
-
<int name="rows">
|
128
|
-
|
138
|
+
<str name="sort">score desc, annotated_at_tdate desc</str>
|
139
|
+
<int name="rows">2500</int>
|
140
|
+
<str name="fl">* score</str>
|
129
141
|
<str name="wt">ruby</str>
|
130
142
|
<str name="indent">true</str>
|
131
143
|
|
@@ -140,46 +152,48 @@
|
|
140
152
|
<str name="df">anno_jsonld</str>
|
141
153
|
<str name="q.op">AND</str>
|
142
154
|
|
143
|
-
|
155
|
+
<str name="qf">
|
144
156
|
body_chars_exact^3
|
145
157
|
body_chars_unstem^2
|
146
158
|
body_chars_stem
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
159
|
+
annotated_by_unstem^2
|
160
|
+
annotated_by_stem
|
161
|
+
target_url
|
162
|
+
body_url
|
163
|
+
motivation
|
164
|
+
id
|
165
|
+
</str>
|
166
|
+
<str name="pf"> <!-- (phrase boost within result set) -->
|
167
|
+
body_chars_exact^15
|
156
168
|
body_chars_unstem^10
|
157
169
|
body_chars_stem^5
|
158
170
|
annotated_by_unstem^10
|
159
171
|
annotated_by_stem^5
|
160
|
-
|
161
|
-
|
172
|
+
</str>
|
173
|
+
<str name="pf3"> <!-- (token trigrams boost within result set) -->
|
162
174
|
body_chars_exact^9
|
163
175
|
body_chars_unstem^6
|
164
176
|
body_chars_stem^3
|
165
177
|
annotated_by_unstem^6
|
166
178
|
annotated_by_stem^3
|
167
|
-
|
168
|
-
|
179
|
+
</str>
|
180
|
+
<str name="pf2"> <!--(token bigrams boost within result set) -->
|
169
181
|
body_chars_exact^6
|
170
182
|
body_chars_unstem^4
|
171
183
|
body_chars_stem^2
|
172
184
|
annotated_by_unstem^4
|
173
185
|
annotated_by_stem^2
|
174
|
-
|
186
|
+
</str>
|
175
187
|
|
176
|
-
|
188
|
+
<bool name="facet">true</bool>
|
177
189
|
<int name="facet.mincount">1</int>
|
190
|
+
<str name="facet.field">root</str>
|
191
|
+
<str name="f.root.facet.method">enum</str>
|
178
192
|
<str name="facet.field">motivation</str>
|
179
193
|
<str name="f.motivation.facet.method">enum</str>
|
180
194
|
<str name="facet.field">target_type</str>
|
181
195
|
<str name="f.target_type.facet.method">enum</str>
|
182
|
-
|
196
|
+
<str name="facet.field">body_type</str>
|
183
197
|
<str name="f.body_type.facet.method">enum</str>
|
184
198
|
<str name="facet.field">annotated_at_tdate</str>
|
185
199
|
|
@@ -191,7 +205,7 @@
|
|
191
205
|
<lst name="defaults">
|
192
206
|
<str name="echoParams">explicit</str>
|
193
207
|
<str name="fl">*</str>
|
194
|
-
<int name="rows">
|
208
|
+
<int name="rows">10</int> <!-- just in case; expecting 1 -->
|
195
209
|
<str name="q">{!raw f=id v=$id}</str> <!-- use id=666 instead of q=id:666 -->
|
196
210
|
<str name="wt">ruby</str>
|
197
211
|
<str name="indent">true</str>
|
@@ -236,4 +250,3 @@
|
|
236
250
|
</admin>
|
237
251
|
|
238
252
|
</config>
|
239
|
-
|
@@ -1,25 +1,47 @@
|
|
1
1
|
require_relative '../../app/services/triannon/ldp_writer'
|
2
2
|
|
3
3
|
namespace :triannon do
|
4
|
-
desc "
|
5
|
-
task :
|
4
|
+
desc "clean out then reset jetty from scratch for Triannon - starts jetty"
|
5
|
+
task :jetty_reset => ['jetty:stop', 'jetty:clean', 'jetty:environment', :jetty_config, 'jetty:start']
|
6
6
|
|
7
|
-
desc "
|
8
|
-
task :
|
7
|
+
desc "configure Fedora and Solr in jetty for triannon"
|
8
|
+
task :jetty_config => [:solr_jetty_config, :disable_fedora_auth_in_jetty]
|
9
|
+
|
10
|
+
# don't display this in rake -T
|
11
|
+
#desc "set up triannon core in jetty Solr"
|
12
|
+
task :solr_jetty_config do
|
9
13
|
`cp -r config/solr/triannon-core jetty/solr`
|
10
14
|
`cp config/solr/solr.xml jetty/solr`
|
15
|
+
`cp config/solr/log4j.properties jetty/resources`
|
11
16
|
end
|
12
17
|
|
13
|
-
|
18
|
+
# don't display this in rake -T
|
19
|
+
#desc "disable fedora basic authorization in jetty"
|
14
20
|
task :disable_fedora_auth_in_jetty do
|
15
21
|
`cp config/jetty/etc/* jetty/etc`
|
16
22
|
end
|
17
23
|
|
18
|
-
|
24
|
+
|
25
|
+
# ------- root container tasks ----------
|
26
|
+
|
27
|
+
# don't display this in rake -T
|
28
|
+
#desc 'ONLY WORKS WITHIN RAILS APP: Create the uber root annotation container per triannon.yml'
|
19
29
|
task :create_uber_root_container do
|
20
30
|
unless File.exist? Triannon.triannon_file
|
21
|
-
puts "Triannon config file missing: #{Triannon.triannon_file}"
|
31
|
+
puts "ERROR: Triannon config file missing: #{Triannon.triannon_file} - are you in the rails app root directory?"
|
32
|
+
raise "Triannon config file missing: #{Triannon.triannon_file}"
|
22
33
|
end
|
23
34
|
Triannon::LdpWriter.create_basic_container(nil, Triannon.config[:ldp]['uber_container'])
|
24
35
|
end
|
25
|
-
|
36
|
+
|
37
|
+
desc "ONLY WORKS WITHIN RAILS APP: Create root anno containers per triannon.yml"
|
38
|
+
task :create_root_containers => :create_uber_root_container do
|
39
|
+
unless File.exist? Triannon.triannon_file
|
40
|
+
puts "ERROR: Triannon config file missing: #{Triannon.triannon_file} - are you in the rails app root directory?"
|
41
|
+
raise "Triannon config file missing: #{Triannon.triannon_file}"
|
42
|
+
end
|
43
|
+
Triannon.config[:ldp]['anno_containers'].each { |container_name|
|
44
|
+
Triannon::LdpWriter.create_basic_container(Triannon.config[:ldp]['uber_container'], container_name)
|
45
|
+
}
|
46
|
+
end
|
47
|
+
end # namespace triannon
|
data/lib/triannon.rb
CHANGED
data/lib/triannon/error.rb
CHANGED
@@ -9,6 +9,20 @@ module Triannon
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
+
# general error for LDP anno root container issues
|
13
|
+
class LDPContainerError < Triannon::Error
|
14
|
+
def initialize(message = nil)
|
15
|
+
super(message)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# used when LDP anno root container doesn't exist
|
20
|
+
class MissingLDPContainerError < Triannon::LDPContainerError
|
21
|
+
def initialize(message = nil)
|
22
|
+
super(message)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
12
26
|
# used to keep HTTP response info from LDP
|
13
27
|
class LDPStorageError < Triannon::Error
|
14
28
|
attr_accessor :ldp_resp_status, :ldp_resp_body
|
data/lib/triannon/version.rb
CHANGED