Permalink
Browse files

basic Solr faceting working

  • Loading branch information...
1 parent 4361915 commit e158b3f97b1517cff54e39e9071a560b67afa067 Charles DeTar committed Sep 8, 2010
View
4 afg/admin.py
@@ -9,4 +9,6 @@ class DiaryAdmin(admin.ModelAdmin):
date_hierarchy = 'date'
admin.site.register(models.DiaryEntry, DiaryAdmin)
-admin.site.register(models.Phrase)
+class PhraseAdmin(admin.ModelAdmin):
+ filter_horizontal = ('entries',)
+admin.site.register(models.Phrase, PhraseAdmin)
View
21 afg/management/commands/import_wikileaks.py
@@ -5,8 +5,7 @@
from collections import defaultdict
from django.core.management.base import BaseCommand
-from django.db import connection
-from django.contrib.gis.geos import GEOSGeometry
+from django.db import connection, transaction
from afg.models import DiaryEntry, Phrase
@@ -69,20 +68,15 @@ def handle(self, *args, **kwargs):
with open(args[0]) as fh:
reader = csv.reader(fh)
- for c, row in enumerate(itertools.islice(reader, 0, 1000)):
+ for c, row in enumerate(reader):
print c
for i in range(13, 22):
row[i] = int(row[i] or 0)
kwargs = dict(zip(fields, row))
- lon, lat = kwargs.pop('longitude'), kwargs.pop('latitude')
- if lon and lat:
- kwargs['point'] = "POINT(%s %s)" % (lon, lat)
kwargs['summary'] = clean_summary(kwargs['summary'])
- kwargs['total_casualties'] = (kwargs['friendly_wia'] + kwargs['friendly_kia'] +
- kwargs['host_nation_wia'] + kwargs['host_nation_kia'] +
- kwargs['civilian_wia'] + kwargs['civilian_kia'] +
- kwargs['enemy_wia'] + kwargs['enemy_kia'])
- entry = DiaryEntry.objects.get_or_create(**kwargs)[0]
+ kwargs['latitude'] = float(kwargs['latitude']) if kwargs['latitude'] else None
+ kwargs['longitude'] = float(kwargs['longitude']) if kwargs['longitude'] else None
+ entry = DiaryEntry.objects.create(**kwargs)
# Get words for phrases
summary = re.sub(r'<[^>]*?>', '', kwargs['summary'])
summary = re.sub(r'&[^;\s]+;', ' ', summary)
@@ -91,11 +85,12 @@ def handle(self, *args, **kwargs):
words = summary.split(' ')
for i in range(3, 1, -1):
for j in range(i, len(words)):
- phrase = Phrase.objects.get_or_create(phrase=" ".join(words[j-i:j])[:255])[0]
+ phrase, created = Phrase.objects.get_or_create(phrase=" ".join(words[j-i:j])[:255])
entry.phrase_set.add(phrase)
# dennormalize entry counts
cursor = connection.cursor()
cursor.execute("""
-UPDATE afg_phrase SET entry_count = (SELECT COUNT(pe.*) FROM afg_phrase_entries pe WHERE pe.phrase_id = afg_phrase.id)
+UPDATE afg_phrase SET entry_count = (SELECT COUNT(pe.*) FROM afg_phrase_entries pe WHERE pe.phrase_id = afg_phrase.id);
""")
+ transaction.commit_unless_managed()
View
13 afg/models.py
@@ -1,4 +1,4 @@
-from django.contrib.gis.db import models
+from django.db import models
# No DB indexes because we're kicking all that to SOLR.
class DiaryEntry(models.Model):
@@ -25,20 +25,19 @@ class DiaryEntry(models.Model):
enemy_kia = models.IntegerField()
enemy_detained = models.IntegerField()
mgrs = models.CharField(max_length=255)
+ latitude = models.FloatField(blank=True, null=True)
+ longitude = models.FloatField(blank=True, null=True)
originator_group = models.CharField(max_length=255)
updated_by_group = models.CharField(max_length=255)
ccir = models.CharField(max_length=255)
sigact = models.CharField(max_length=255)
affiliation = models.CharField(max_length=255)
dcolor = models.CharField(max_length=255)
classification = models.CharField(max_length=255)
- # GIS point
- point = models.PointField(blank=True, null=True)
# denormalization for sorting
- total_casualties = models.IntegerField(default=0)
-
- objects = models.GeoManager()
+ def total_casualties(self):
+ return self.friendly_wia + self.friendly_kia + self.host_nation_wia + self.host_nation_kia + self.civilian_wia + self.civilian_kia + self.enemy_wia + self.enemy_kia
def __unicode__(self):
return self.title
@@ -50,7 +49,7 @@ def to_dict(self):
return obj
class Meta:
- ordering = ['-total_casualties']
+ ordering = ['date']
verbose_name_plural = 'Diary entries'
def casualty_summary(self):
View
4 afg/search_indexes.py
@@ -28,14 +28,16 @@ class DiaryEntryIndex(indexes.SearchIndex):
enemy_kia = indexes.IntegerField(model_attr='enemy_kia', faceted=True)
enemy_detained = indexes.IntegerField(model_attr='enemy_detained', faceted=True)
mgrs = indexes.CharField(model_attr='mgrs', faceted=True)
+ latitude = indexes.FloatField(model_attr='latitude', null=True)
+ longitude = indexes.FloatField(model_attr='longitude', null=True)
originator_group = indexes.CharField(model_attr='originator_group', faceted=True)
updated_by_group = indexes.CharField(model_attr='updated_by_group', faceted=True)
ccir = indexes.CharField(model_attr='ccir', faceted=True)
sigact = indexes.CharField(model_attr='sigact', faceted=True)
affiliation = indexes.CharField(model_attr='affiliation', faceted=True)
dcolor = indexes.CharField(model_attr='dcolor', faceted=True)
classification = indexes.CharField(model_attr='classification', faceted=True)
- point = indexes.CharField(model_attr='point', null=True)
+ total_casualties = indexes.IntegerField(model_attr='total_casualties', faceted=True)
def get_queryset(self):
return DiaryEntry.objects.all()
View
4 afg/templates/afg/search.html
@@ -16,9 +16,9 @@
{% for choice in choice_opts.choices %}
<li>
{% if choice_opts.choices|length > 1 %}
- <a href="{{ qstring }}&{{ param }}={{choice.1}}">{% firstof choice.0 "None" %}</a>
+ <a href="{{ qstring }}&{{ param }}={{choice.1}}">{% firstof choice.0 "None" %}</a> ({{ choice.2 }})
{% else %}
- {% firstof choice.0 "None" %}
+ {% firstof choice.0 "None" %} ({{ choice.2 }})
{% endif %}
</li>
{% endfor %}
View
275 afg/views.py
@@ -1,6 +1,7 @@
import re
import urllib
import random
+import datetime
from collections import defaultdict
from django.http import Http404
@@ -9,7 +10,12 @@
from django.core import paginator
from django.core.urlresolvers import reverse
+from haystack.query import SearchQuerySet
+from haystack.utils import Highlighter
+import haystack
+
from afg.models import DiaryEntry, Phrase
+from afg.search_indexes import DiaryEntryIndex
from afg import utils
def about(request):
@@ -94,28 +100,19 @@ def random_entry(request):
report_key = DiaryEntry.objects.all()[random.randint(0, count)].report_key
return utils.redirect_to("afg.show_entry", report_key)
-def _fix_amps(haystack):
- amps = re.compile("&amp;", re.I)
- while True:
- fixed = amps.sub("&", haystack)
- if fixed == haystack:
- break
- haystack = fixed
- return re.sub("&(?![A-Za-z0-9#]+;)", "&amp;", haystack)
-
-def _excerpt(haystack, needles):
+def _excerpt(text, needles):
+ print needles
if not needles:
i = 200
- while i < len(haystack) and haystack[i] != " ":
+ while i < len(text) and text[i] != " ":
i += 1
- return haystack[0:i] + "..."
+ return text[0:i] + "..."
- haystack = re.sub("\s+", " ", haystack)
- haystack = _fix_amps(haystack)
+ text = re.sub("\s+", " ", text)
words = [re.sub("[^-A-Z0-9 ]", "", needle.upper()) for needle in needles]
locations = defaultdict(list)
for word in words:
- for match in re.finditer(word, haystack, re.I):
+ for match in re.finditer(word, text, re.I):
locations[word].append(match.start())
winner = {}
@@ -152,16 +149,16 @@ def _excerpt(haystack, needles):
snips = sorted(winner.items())
n = 0
for loc, word in snips:
- snipped.append((haystack[n:loc], 0))
- snipped.append((haystack[loc:loc+len(word)], 1))
+ snipped.append((text[n:loc], 0))
+ snipped.append((text[loc:loc+len(word)], 1))
n = loc + len(word)
- snipped.append((haystack[n:], 0))
+ snipped.append((text[n:], 0))
out = []
for i, (snip, bold) in enumerate(snipped):
if bold:
- out.append("<b>")
+ out.append("<em>")
out.append(snip)
- out.append("</b>")
+ out.append("</em>")
else:
if len(snip) > 100:
if i != 0:
@@ -173,144 +170,180 @@ def _excerpt(haystack, needles):
out.append(snip)
return mark_safe("".join(out))
else:
- return haystack[0:200]
+ return text[0:200]
def api(request):
return utils.render_request(request, "afg/api.html")
-SEARCH_PARAMS = {
- 'q': ('q', unicode),
- 'date__day': ('date__day', int),
- 'date__year': ('date__year', int),
- 'date__month': ('date__month', int),
- 'category': ('category', unicode),
- 'type': ('type', unicode),
- 'region': ('region', unicode),
- 'attack_on': ('attack_on', unicode),
- 'complex_attack': ('complex_attack', lambda e: "yes" if e else "no"),
- 'unit_name': ('unit_name', unicode),
- 'type_of_unit': ('type_of_unit', unicode),
- 'reporting_unit': ('reporting_unit', unicode),
- 'friendly_wia__gte': ('friendly_wia__gte', int),
- 'friendly_wia__lte': ('friendly_wia__lte', int),
- 'host_nation_wia__gte': ('host_nation_wia__gte', int),
- 'host_nation_wia__lte': ('host_nation_wia__lte', int),
- 'civilian_wia__gte': ('civilian_wia__gte', int),
- 'civilian_wia__lte': ('civilian_wia__lte', int),
- 'enemy_wia__gte': ('enemy_wia__gte', int),
- 'enemy_wia__lte': ('enemy_wia__lte', int),
- 'friendly_kia__gte': ('friendly_kia__gte', int),
- 'friendly_kia__lte': ('friendly_kia__lte', int),
- 'host_nation_kia__gte': ('host_nation_kia__gte', int),
- 'host_nation_kia__lte': ('host_nation_kia__lte', int),
- 'civilian_kia__gte': ('civilian_kia__gte', int),
- 'civilian_kia__lte': ('civilian_kia__lte', int),
- 'enemy_kia__gte': ('enemy_kia__gte', int),
- 'enemy_kia__lte': ('enemy_kia__lte', int),
- 'enemy_detained__gte': ('enemy_detained__gte', int),
- 'enemy_detained__lte': ('enemy_detained__lte', int),
- 'mgrs': ('mgrs', unicode),
- 'originator_group': ('originator_group', unicode),
- 'updated_by_group': ('updated_by_group', unicode),
- 'affiliation': ('affiliation', unicode),
- 'dcolor': ('dcolor', unicode),
- 'classification': ('classification', unicode),
-}
-
def search(request, about=False, api=False):
+ sqs = SearchQuerySet()
params = {}
- for key in request.GET:
- trans = SEARCH_PARAMS.get(key, None)
- if trans and request.GET[key]:
- try:
- params[trans[0]] = trans[1](request.GET[key])
- except ValueError:
- continue
+
+ text_facets = ('type_', 'region', 'attack_on', 'type_of_unit', 'affiliation',
+ 'dcolor', 'classification', 'category')
+ integer_facets = ('civilian_kia', 'civilian_wia', 'host_nation_kia', 'host_nation_wia',
+ 'friendly_kia', 'friendly_wia', 'enemy_kia', 'enemy_wia', 'enemy_detained')
+ # prepare fields for faceting. `date` is special-cased later.
+ for facet in text_facets:
+ sqs = sqs.facet(facet)
+ for facet in integer_facets:
+ sqs = sqs.facet(facet)
+
+ # Full text search
+ q = request.GET.get('q', None)
+ if q:
+ sqs = sqs.auto_query(q).highlight()
+ params['q'] = q
+
+ # Narrow query set by given facets
+ for key,val in request.GET.iteritems():
+ if val:
+ val == sqs.query.clean(val)
+ # Add an "exact" param and split by '__'. If the field already has
+ # e.g. __gte, the __exact addendum is ignored, since we only look
+ # at the first two parts.
+ field_name, lookup = (key + "__exact").rsplit(r'__')[0:2]
+ field_name = "type_" if field_name == "type" else field_name
+ field = DiaryEntryIndex.fields.get(field_name, None)
+ if field:
+ if lookup == 'exact':
+ sqs = sqs.narrow(u'%s:"%s"' % (field.index_fieldname, val))
+ elif lookup == 'gte':
+ sqs = sqs.narrow(u"%s:[%s TO *]" % val)
+ elif lookup == 'lte':
+ sqs = sqs.narrow(u"%s:[* TO %s]" % val)
+ else:
+ continue
+ params[key] = val
+ # Narrow query set by given dates
+ day = int(request.GET.get('date__day', 0))
+ month = int(request.GET.get('date__month', 0))
+ year = int(request.GET.get('date__year', 0))
+ if year:
+ if not month:
+ start = datetime.datetime(year, 1, 1)
+ end = datetime.datetime(year + 1, 1, 1) - datetime.timedelta(seconds=1)
+ params['date__year'] = year
+ sqs = sqs.date_facet('date', start, end, 'month')
+ elif not day:
+ start = datetime.datetime(year, month, 1)
+ next_month = datetime.datetime(year, month, 1) + datetime.timedelta(days=31)
+ end = datetime.datetime(next_month.year, next_month.month, 1) - datetime.timedelta(seconds=1)
+ params['date__year'] = year
+ params['date__month'] = month
+ sqs = sqs.date_facet('date', start, end, 'day')
+ else:
+ start = datetime.datetime(year, month, day)
+ end = datetime.datetime(year, month, day + 1) - datetime.timedelta(seconds=1)
+ params['date__year'] = year
+ params['date__month'] = month
+ params['date__day'] = day
+ sqs = sqs.date_facet('date', start, end, 'day')
+ sqs = sqs.narrow("date:[%s TO %s]" % (start.isoformat() + "Z", end.isoformat() + "Z"))
+ else:
+ start = datetime.datetime(2004, 1, 1, 0, 0, 0)
+ end = datetime.datetime.now()
+ sqs = sqs.date_facet('date', start, end, 'year')
+
# sorting
sort_by = request.GET.get('sort_by', 'date')
sort_dir = request.GET.get('sort_dir', 'asc')
- # special handling of full text search
- q = params.pop('q', None)
- if q:
- qs = DiaryEntry.objects.extra(where=['summary_tsv @@ plainto_tsquery(%s)'], params=[q])
- else:
- qs = DiaryEntry.objects.all()
- qs = qs.filter(**params)
direction_indicator = '-' if sort_dir == 'desc' else ''
if sort_by in ('date', 'total_casualties'):
- qs = qs.order_by(direction_indicator + sort_by)
-
- # Restore params now that we've finished filtering on the non-model elements
- if q:
- params['q'] = q
+ sqs = sqs.order_by(direction_indicator + sort_by)
params['sort_by'] = sort_by
params['sort_dir'] = sort_dir
-
- p = paginator.Paginator(qs, 10)
+ # Pagination
+ p = paginator.Paginator(sqs.load_all(), 10)
try:
page = p.page(int(request.GET.get('p', 1)))
except (ValueError, paginator.InvalidPage, paginator.EmptyPage):
page = p.page(p.num_pages)
- if q:
- needles = q.split()
- else:
- needles = None
- entries = [(entry, _excerpt(entry.summary, needles)) for entry in page.object_list]
+ # Results Summaries and highlighting
+ entries = []
+ for entry in page.object_list:
+ if entry.highlighted:
+ excerpt = mark_safe(u"... %s ..." % entry.highlighted['text'][0])
+ else:
+ excerpt = entry.summary[0:200] + "..."
+ entries.append((entry, excerpt))
+ # Choices
+ total_count = sqs.count()
+ counts = sqs.facet_counts()
choices = utils.OrderedDict()
+ date_facets = []
+ for d,c in sorted(counts['dates']['date'].iteritems()):
+ try:
+ # magic method to parse ISO date format.
+ dt = datetime.datetime(*map(int, re.split('[^\d]', d)[:-1]))
+ if c > 0:
+ date_facets.append((dt, c))
+ except (TypeError, ValueError):
+ pass
# Date choices
choices['date__year'] = {
- 'title': 'Year',
- 'choices': [(d.year, d.year) for d in qs.dates('date', 'year')],
- 'value': params.get('date__year', ''),
+ 'title': 'Year',
+ 'value': params.get('date__year', ''),
}
- if 'date__year' in params or 'date__month' in params:
+ year = params.get('date__year', '')
+ if year:
+ choices['date__year']['choices'] = [(year, year, total_count)]
+ month = params.get('date__month', '')
choices['date__month'] = {
'title': 'Month',
- 'choices': sorted(set((d.strftime("%B"), d.month) for d in qs.dates('date', 'month'))),
- 'value': params.get('date__month', ''),
- }
- if ('date__year' in params and 'date__month' in params) or 'date__day' in params:
- choices['date__day'] = {
- 'title': 'Day',
- 'choices': [(d.day, d.day) for d in qs.dates('date', 'day')],
- 'value': params.get('date__day', ''),
+ 'value': month
}
+ if month:
+ choices['date__month']['choices'] = [(date_facets[0][0].strftime("%B"), month, total_count)]
+ day = params.get('date__day', '')
+ choices['date__day'] = {
+ 'title': 'Day',
+ 'value': day
+ }
+ if day:
+ choices['date__day']['choices'] = [(day, day, total_count)]
+ else:
+ choices['date__day']['choices'] = [(d.day, d.day, c) for d, c in date_facets]
+ else:
+ choices['date__month']['choices'] = [(d.strftime("%B"), d.month, c) for d, c in date_facets]
+ else:
+ choices['date__year']['choices'] = [(d.year, d.year, c) for d, c in date_facets]
+ params.pop('date__month', '')
+ params.pop('date__day', '')
- # General field choices
- for field in ('type', 'region', 'attack_on', 'type_of_unit',
- 'affiliation', 'dcolor', 'classification', 'category'):
- cs = list(q.values()[0] for q in qs.distinct().order_by(field).values(field))
+ # Text field choices
+ for field in text_facets + integer_facets:
choices[field] = {
'title': field.replace('_', ' ').title(),
- 'choices': zip(cs, cs),
+ 'choices': sorted((k, k, c) for k, c in counts['fields'][field] if c > 0),
'value': params.get(field, ''),
}
min_max_choices = utils.OrderedDict()
- # Integer choices
- for field in ('total_casualties', 'civilian_kia', 'civilian_wia', 'host_nation_kia', 'host_nation_wia', 'friendly_kia', 'friendly_wia', 'enemy_kia', 'enemy_wia', 'enemy_detained'):
- try:
- minimum = qs.order_by(field).values(field)[0][field]
- maximum = qs.order_by("-%s" % field).values(field)[0][field]
- except IndexError:
- continue
- if minimum == maximum and \
- not params.get(field + '__gte') and \
- not params.get(field + '__lte'):
- continue
- min_max_choices[field] = {
- 'min': minimum,
- 'max': maximum,
- 'title': fix_constraint_name(field),
- 'min_value': params.get(field + '__gte', ''),
- 'max_value': params.get(field + '__lte', ''),
- }
+# # Integer choices
+# for field in integer_facets:
+# try:
+# minimum = qs.order_by(field).values(field)[0][field]
+# maximum = qs.order_by("-%s" % field).values(field)[0][field]
+# except IndexError:
+# continue
+# if minimum == maximum and \
+# not params.get(field + '__gte') and \
+# not params.get(field + '__lte'):
+# continue
+# min_max_choices[field] = {
+# 'min': minimum,
+# 'max': maximum,
+# 'title': fix_constraint_name(field),
+# 'min_value': params.get(field + '__gte', ''),
+# 'max_value': params.get(field + '__lte', ''),
+# }
search_url = reverse('afg.search')
View
3 default_settings.py
@@ -46,7 +46,7 @@
# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
-MEDIA_ROOT = os.path.join(SETTINGS_ROOT, '/media/')
+MEDIA_ROOT = os.path.join(SETTINGS_ROOT, 'media/')
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
@@ -93,7 +93,6 @@
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
- 'django.contrib.gis',
'django.contrib.admin',
#'johnny',
'haystack',
View
2 media/css/sass/style.sass
@@ -34,6 +34,8 @@ p
font-family: monospace
small
font-size: 0.8em
+em
+ font-weight: bold
strong
font-weight: bold
font-size: larger
View
107 media/css/style.css
@@ -1,4 +1,4 @@
-/* line 14, /var/lib/gems/1.8/gems/compass-0.10.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
+/* line 14, /var/lib/gems/1.8/gems/compass-0.10.5/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
@@ -18,42 +18,42 @@ table, caption, tbody, tfoot, thead, tr, th, td {
vertical-align: baseline;
}
-/* line 17, /var/lib/gems/1.8/gems/compass-0.10.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
+/* line 17, /var/lib/gems/1.8/gems/compass-0.10.5/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
body {
line-height: 1;
color: black;
background: white;
}
-/* line 19, /var/lib/gems/1.8/gems/compass-0.10.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
+/* line 19, /var/lib/gems/1.8/gems/compass-0.10.5/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
ol, ul {
list-style: none;
}
-/* line 21, /var/lib/gems/1.8/gems/compass-0.10.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
+/* line 21, /var/lib/gems/1.8/gems/compass-0.10.5/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
table {
border-collapse: separate;
border-spacing: 0;
vertical-align: middle;
}
-/* line 23, /var/lib/gems/1.8/gems/compass-0.10.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
+/* line 23, /var/lib/gems/1.8/gems/compass-0.10.5/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
caption, th, td {
text-align: left;
font-weight: normal;
vertical-align: middle;
}
-/* line 25, /var/lib/gems/1.8/gems/compass-0.10.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
+/* line 25, /var/lib/gems/1.8/gems/compass-0.10.5/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
q, blockquote {
quotes: "" "";
}
-/* line 96, /var/lib/gems/1.8/gems/compass-0.10.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
+/* line 96, /var/lib/gems/1.8/gems/compass-0.10.5/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
q:before, q:after, blockquote:before, blockquote:after {
content: "";
}
-/* line 27, /var/lib/gems/1.8/gems/compass-0.10.2/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
+/* line 27, /var/lib/gems/1.8/gems/compass-0.10.5/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
a img {
border: none;
}
@@ -123,91 +123,96 @@ small {
}
/* line 37, ././style.sass */
+em {
+ font-weight: bold;
+}
+
+/* line 39, ././style.sass */
strong {
font-weight: bold;
font-size: larger;
}
-/* line 40, ././style.sass */
+/* line 42, ././style.sass */
li {
list-style-type: disc;
margin-left: 1em;
}
-/* line 43, ././style.sass */
+/* line 45, ././style.sass */
li.searchresult {
list-style-type: none;
margin-top: 1.5em;
}
-/* line 46, ././style.sass */
+/* line 48, ././style.sass */
table {
border-collapse: collapse;
}
-/* line 48, ././style.sass */
+/* line 50, ././style.sass */
acronym, .toggle-acronyms {
color: #880000;
}
-/* line 52, ././style.sass */
+/* line 54, ././style.sass */
.links {
border-bottom: 1px solid #eeffee;
cursor: pointer;
color: #003300;
}
-/* line 57, ././style.sass */
+/* line 59, ././style.sass */
.numlinks1 {
border-bottom: 1px solid #ddffdd;
}
-/* line 59, ././style.sass */
+/* line 61, ././style.sass */
.numlinks2 {
border-bottom: 2px solid #ddffdd;
}
-/* line 61, ././style.sass */
+/* line 63, ././style.sass */
.numlinks3 {
border-bottom: 3px solid #ddffdd;
}
-/* line 63, ././style.sass */
+/* line 65, ././style.sass */
.numlinks4 {
border-bottom: 4px solid #ddffdd;
}
-/* line 65, ././style.sass */
+/* line 67, ././style.sass */
.numlinks5 {
border-bottom: 5px solid #ddffdd;
}
-/* line 67, ././style.sass */
+/* line 69, ././style.sass */
.numlinks6 {
border-bottom: 6px solid #ddffdd;
}
-/* line 69, ././style.sass */
+/* line 71, ././style.sass */
.numlinks7 {
border-bottom: 7px solid #ddffdd;
}
-/* line 71, ././style.sass */
+/* line 73, ././style.sass */
.numlinks8 {
border-bottom: 8px solid #ddffdd;
}
-/* line 73, ././style.sass */
+/* line 75, ././style.sass */
.numlinks9 {
border-bottom: 9px solid #ddffdd;
}
-/* line 75, ././style.sass */
+/* line 77, ././style.sass */
.numlinks10 {
border-bottom: 10px solid #ddffdd;
}
-/* line 78, ././style.sass */
+/* line 80, ././style.sass */
.popup {
max-width: 80%;
position: absolute;
@@ -216,7 +221,7 @@ acronym, .toggle-acronyms {
padding-top: 2em;
background-color: white;
}
-/* line 85, ././style.sass */
+/* line 87, ././style.sass */
.popup .close {
position: absolute;
right: 0.2em;
@@ -225,76 +230,72 @@ acronym, .toggle-acronyms {
text-decoration: underline;
cursor: pointer;
}
-/* line 92, ././style.sass */
+/* line 94, ././style.sass */
.popup p {
margin: 0;
}
-/* line 95, ././style.sass */
+/* line 97, ././style.sass */
.logo {
text-align: center;
}
-/* line 97, ././style.sass */
+/* line 99, ././style.sass */
.logo a, .logo a:link, .logo a:visited {
color: #000099;
text-decoration: none;
}
-/* line 100, ././style.sass */
+/* line 102, ././style.sass */
.logo h1 {
font-size: 24pt;
}
-/* line 102, ././style.sass */
+/* line 104, ././style.sass */
.logo h2 {
font-size: 12pt;
}
-/* line 105, ././style.sass */
+/* line 107, ././style.sass */
.date {
color: #555555;
}
-/* line 107, ././style.sass */
+/* line 109, ././style.sass */
.category, .region, .casualties {
color: #550000;
}
-/* line 110, ././style.sass */
+/* line 112, ././style.sass */
.summary {
line-height: 2em;
}
-/* line 113, ././style.sass */
+/* line 115, ././style.sass */
.metadata {
font-size: smaller;
}
-/* line 115, ././style.sass */
+/* line 117, ././style.sass */
.metadata th {
font-weight: bold;
}
-/* line 117, ././style.sass */
+/* line 119, ././style.sass */
.metadata th, .metadata td {
text-align: right;
border: 1px solid #dddddd;
padding: 0.5em;
}
-/* line 121, ././style.sass */
+/* line 123, ././style.sass */
.metadata td + td {
text-align: center;
}
-/* line 124, ././style.sass */
+/* line 126, ././style.sass */
.entry {
width: 950px;
margin: 0 auto;
overflow: hidden;
- display: inline-block;
-}
-/* line 8, /var/lib/gems/1.8/gems/compass-0.10.2/frameworks/compass/stylesheets/compass/utilities/general/./_hacks.scss */
-.entry {
- display: block;
+ *zoom: 1;
}
-/* line 127, ././style.sass */
+/* line 129, ././style.sass */
.sidebar {
float: left;
margin-right: 1em;
@@ -304,12 +305,12 @@ acronym, .toggle-acronyms {
margin-right: 10px;
width: 270px;
}
-/* line 138, /var/lib/gems/1.8/gems/compass-0.10.2/frameworks/blueprint/stylesheets/./blueprint/_grid.scss */
+/* line 139, /var/lib/gems/1.8/gems/compass-0.10.5/frameworks/blueprint/stylesheets/./blueprint/_grid.scss */
* html .sidebar {
overflow-x: hidden;
}
-/* line 133, ././style.sass */
+/* line 135, ././style.sass */
.about {
margin-top: 3em;
width: 649px;
@@ -318,40 +319,40 @@ acronym, .toggle-acronyms {
margin-right: 0;
width: 670px;
}
-/* line 138, /var/lib/gems/1.8/gems/compass-0.10.2/frameworks/blueprint/stylesheets/./blueprint/_grid.scss */
+/* line 139, /var/lib/gems/1.8/gems/compass-0.10.5/frameworks/blueprint/stylesheets/./blueprint/_grid.scss */
* html .about {
overflow-x: hidden;
}
-/* line 137, ././style.sass */
+/* line 139, ././style.sass */
.main {
width: 649px;
display: inline;
float: left;
margin-right: 0;
width: 670px;
}
-/* line 138, /var/lib/gems/1.8/gems/compass-0.10.2/frameworks/blueprint/stylesheets/./blueprint/_grid.scss */
+/* line 139, /var/lib/gems/1.8/gems/compass-0.10.5/frameworks/blueprint/stylesheets/./blueprint/_grid.scss */
* html .main {
overflow-x: hidden;
}
-/* line 143, ././style.sass */
+/* line 145, ././style.sass */
.constraints {
background-color: #eeeeee;
padding: 1em;
}
-/* line 146, ././style.sass */
+/* line 148, ././style.sass */
.constraints .constraint {
background-color: #ffaa33;
padding: 0.2em;
margin-right: 1em;
}
-/* line 150, ././style.sass */
+/* line 152, ././style.sass */
.constraints .sort {
float: right;
}
-/* line 152, ././style.sass */
+/* line 154, ././style.sass */
.constraints .sort a.sortdir, .constraints .sort a.sortdir:visited {
text-decoration: none;
}
View
8 reset_afgexplorer.sh
@@ -4,6 +4,10 @@ DBNAME=afg2
DBUSER=afg2
sudo su postgres -c "dropdb $DBNAME"
-sudo su postgres -c "createdb -T template_postgis -O $DBUSER $DBNAME"
+sudo su postgres -c "createdb -O $DBUSER $DBNAME"
python manage.py syncdb --noinput
-#sudo su postgres -c "psql $DBNAME $DBUSER < data/afg.sql"
+python manage.py import_wikileaks data/afg.csv
+python manage.py build_solr_schema > schema.xml
+echo "Please reset Solr now to reflect the new schema, then press [Enter]"
+read foo
+python manage.py rebuild_index
View
10 schema.xml
@@ -78,8 +78,6 @@
<dynamicField name="*_dt" type="date" indexed="true" stored="true"/>
- <field name="point" type="text" indexed="true" stored="true" multiValued="false" />
-
<field name="unit_name" type="text" indexed="true" stored="true" multiValued="false" />
<field name="unit_name_exact" type="string" indexed="true" stored="true" multiValued="false" />
@@ -122,6 +120,10 @@
<field name="type_of_unit_exact" type="string" indexed="true" stored="true" multiValued="false" />
+ <field name="total_casualties" type="slong" indexed="true" stored="true" multiValued="false" />
+
+ <field name="total_casualties_exact" type="slong" indexed="true" stored="true" multiValued="false" />
+
<field name="title" type="text" indexed="true" stored="true" multiValued="false" />
<field name="dcolor" type="text" indexed="true" stored="true" multiValued="false" />
@@ -140,6 +142,8 @@
<field name="civilian_kia_exact" type="slong" indexed="true" stored="true" multiValued="false" />
+ <field name="latitude" type="sfloat" indexed="true" stored="true" multiValued="false" />
+
<field name="host_nation_wia" type="slong" indexed="true" stored="true" multiValued="false" />
<field name="host_nation_wia_exact" type="slong" indexed="true" stored="true" multiValued="false" />
@@ -182,6 +186,8 @@
<field name="region_exact" type="string" indexed="true" stored="true" multiValued="false" />
+ <field name="longitude" type="sfloat" indexed="true" stored="true" multiValued="false" />
+
<field name="summary" type="text" indexed="true" stored="true" multiValued="false" />
<field name="tracking_number" type="text" indexed="true" stored="true" multiValued="false" />
View
2 urls.py
@@ -9,7 +9,7 @@
(r'^admin/', include(admin.site.urls)),
(r'', include('afg.urls')),
)
-if True: # settings.DEBUG
+if settings.DEBUG:
urlpatterns += patterns('',
(r'^%s/(?P<path>.*)$' % settings.MEDIA_URL[1:-1],
'django.views.static.serve',

0 comments on commit e158b3f

Please sign in to comment.