<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Yun Fu&#039;s Worklog &#187; system</title>
	<atom:link href="http://fuyun.org/category/system/feed/" rel="self" type="application/rss+xml" />
	<link>http://fuyun.org</link>
	<description>a system engineer&#039;s blog</description>
	<lastBuildDate>Mon, 02 Jan 2012 05:43:21 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Add Solr Spatial Search for Django Haystack</title>
		<link>http://fuyun.org/2011/11/add-solr-spatial-search-for-djang-haystack/</link>
		<comments>http://fuyun.org/2011/11/add-solr-spatial-search-for-djang-haystack/#comments</comments>
		<pubDate>Sun, 20 Nov 2011 06:21:49 +0000</pubDate>
		<dc:creator>yfu</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[system]]></category>

		<guid isPermaLink="false">http://www.fuyun.org/?p=364</guid>
		<description><![CDATA[Solr has native support of spatial search in the latest release Solr 3.4. However, Django Haystack does not support it yet. Some very helpful discussions about the issue can be found in the Haystack Google group. But, the patch discussed &#8230; <a href="http://fuyun.org/2011/11/add-solr-spatial-search-for-djang-haystack/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Solr has native support of <a href="http://wiki.apache.org/solr/SpatialSearch">spatial search</a> in the latest release Solr 3.4. However, <a href="http://haystacksearch.org/">Django Haystack</a> does not support it yet. Some very helpful discussions about the issue can be found in <a href="http://groups.google.com/group/django-haystack/browse_thread/thread/d0e23d45c0baa300/2298b6cf43389e18">the Haystack Google group</a>. But, <a href="http://friendpaste.com/6y88Nn4tCyRkBmxOOdg8He">the patch </a> discussed in the post is about <a href="http://www.searchworkings.org/blog/-/blogs/ssp-2-0-spatial-search-plugin-for-solr">JTeam&#8217;s SSP plugin</a>, not the Solr <a href="http://wiki.apache.org/solr/SpatialSearch"> native spatial search</a>. I followed the discussion and did similar changes to support this.</p>
<p>Basically. we need two changes.<br />
1. Add a new Solr field type <a href="http://wiki.apache.org/solr/SpatialSearch#LatLonType">LatLonType</a> into the schema generated by Haystack.<br />
2. Support search parameters for spatial queries such as <code>&#038;fq={!geofilt pt=45.15,-93.85 sfield=store d=5}</code>.</p>
<p>Here are the details of the changes:</p>
<p><strong>Step 1. Add LatLonType</strong></p>
<p>As described in <a href="http://wiki.apache.org/solr/SpatialSearch">spatial search wiki</a>, spatial fields should be defined as LatLonType. To support this, we need to add a type definition for LatLonType in Solr schema. Haystack generates schemas just as Django rendering HTML. It is based on a template file, <code>haystack/templates/search_configuration/solr.xml</code>. We need to add the following lines in section <code>"types"</code> and section <code>"fields"</code>.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;schema name=&quot;default&quot; version=&quot;1.1&quot;&gt;
  &lt;types&gt;
  ...
  &lt;!-- A specialized field for geospatial search. If indexed, this fieldType must not be multivalued. --&gt;
  &lt;fieldType name=&quot;location&quot; class=&quot;solr.LatLonType&quot; subFieldSuffix=&quot;_coordinate&quot;/&gt;
  &lt;fieldType name=&quot;tdouble&quot; class=&quot;solr.TrieDoubleField&quot; precisionStep=&quot;8&quot; omitNorms=&quot;true&quot; positionIncrementGap=&quot;0&quot;/&gt;
  &lt;/types&gt;
  &lt;fields&gt;
  ...
  &lt;!-- Type used to index the lat and lon components for the &quot;location&quot; FieldType --&gt;
  &lt;dynamicField name=&quot;*_coordinate&quot;  type=&quot;tdouble&quot; indexed=&quot;true&quot;  stored=&quot;false&quot;/&gt;
  ...
  &lt;/fields&gt;
</pre>
<p>Field type <code>"location"</code> needs <code>"*_coordinate"</code> fields to store latitude and longitude. Fields <code>"*_coordinate"</code> are of type <code>"tdouble"</code>. That&#8217;s why we need these 3 lines.</p>
<p>Correspondingly. we need to add a new search field type <code>LocationField</code> in <code>haystack/fields.py</code> as follows. We introduce two constructor parameters <code>model_lat_attr</code> and <code>model_lng_attr</code> to specify the names of latitude and longitude fields in the indexed Django model just as <a href="http://docs.haystacksearch.org/dev/searchfield_api.html#model-attr">model_attr</a> in SearchField.</p>
<pre class="brush: python; title: ; notranslate">
class LocationField(SearchField):
    field_type = 'location'

    def __init__(self, model_lat_attr=None, model_lng_attr=None, **kwargs):
        if kwargs.get('faceted') is True:
            raise SearchFieldError(&quot;%s can not be faceted.&quot; % self.__class__.__name__)
        super(LocationField, self).__init__(**kwargs)
        self.model_lat_attr = model_lat_attr
        self.model_lng_attr = model_lng_attr

    def prepare(self, obj):
        if self.model_lat_attr != None and self.model_lng_attr != None:
            lat = getattr(obj, self.model_lat_attr, None)
            lng = getattr(obj, self.model_lng_attr, None)
            if lat != None and lng != None:
                location = '%s,%s'%(obj.lat, obj.lng)
                return self.convert(location)
        return self.convert(super(LocationField, self).prepare(obj))

    def convert(self, value):
        if value is None:
            return None
        return unicode(value)
</pre>
<p>Notice the line <code>"field_type = 'location'"</code>. It tells Haystack that <code>LocationField</code> is of the location type we defined in the above schema. But to enable this, we also need to add the following line in <code>backends/solr_backend.py</code>. When executing <code>"manage.py build_solr_schema"</code>, the following method <code>build_schema</code> will be called.</p>
<pre class="brush: python; title: ; notranslate">
class SearchBackend(BaseSearchBackend):
    def build_schema(self, fields):
            ...
            elif field_class.field_type == 'location':
                field_data['type'] = 'location'
</pre>
<p>I don&#8217;t like this kind of hard coding change. It is not very object oriented. Ideally method <code>build_schema</code> should automatically use the <code>field_type</code> defined in <code>LocationField</code> and put it in schema. In that way, we do not need to change the Haystack code. Instead we can define the inherited <code>LocationField</code> in our own code. However, this is just the beginning. We have more hard coding changes in step 2.</p>
<p>With the above code changes, we can define search indices for Django models using LocationField. For example,</p>
<pre class="brush: python; title: ; notranslate">
class Store(models.Model):
    name = models.CharField(max_length=100)
    lat = models.DecimalField(max_digits=10, decimal_places=6)
    lng = models.DecimalField(max_digits=10, decimal_places=6)

class StoreIndex(RealTimeSearchIndex):
    name = CharField(model_attr='name', document=True)
    loc = LocationField(model_lat_attr='lat', model_lng_attr='lng')

site.register(Store, StoreIndex)
</pre>
<p><strong>Step 2. Add spatial search query support</strong></p>
<p><code>SearchQuerySet</code> is the user interface in Haystack to query Solr. To pass spatial search query parameters to Solr, we add a method <code>'spatial'</code> for <code>SearchQuerySet</code> in <code>haystack/query.py</code>.</p>
<pre class="brush: python; title: ; notranslate">
class SearchQuerySet(object):
    ...
    def spatial(self, **kwargs):
        &quot;&quot;&quot;Adds spatial search to the query&quot;&quot;&quot;
        clone = self._clone()
        clone.query.add_spatial(**kwargs)
        return clone
</pre>
<p><code>SearchQuerySet</code> is similar to Django <code>QuerySet</code>, mainly used for chaining queries such as method <code>spatial</code> we just added. The queries are accumulated and evaluated together later. Notice method <code>spatial</code> passes all parameters to method <code>add_spatial</code>, which is defined in <code>haystack/backends/__init__.py</code> as follows.</p>
<pre class="brush: python; title: ; notranslate">
from haystack.exceptions import SpatialError

class BaseSearchQuery(object):
    def __init__(self, using=DEFAULT_ALIAS):
        ...
        self.spatial_query = {}

    def add_spatial(self, **kwargs):
        if 'lat' not in kwargs or 'lng' not in kwargs or 'd' not in kwargs or 'sfield' not in kwargs:
            raise SpatialError(&quot;Spatial queries must contains args lat, lng, d and sfield&quot;)
        if 'filter' not in kwargs:
            kwargs['filter'] = 'geofilt'
        self.spatial_query.update(kwargs)

    def _clone(self, klass=None, using=None):
        ...
        clone.spatial_query = self.spatial_query.copy()
</pre>
<p>As you can see, to do a spatial search, we need to provide at least 4 parameters: <code>lat, lng, d, and sfield</code> as defined in the <a href="http://wiki.apache.org/solr/SpatialSearch">Solr wiki</a>. We can also specify what spatial filter to use, which can be either <code>geofilt</code> (default) or <code>bbox</code>. For example, the following query matches all items with latitude=45.15, longitude=-93.85, within 5 kilometers sorted by distance in ascending order. The filter in this example is <code>bbox</code>.</p>
<pre class="brush: python; title: ; notranslate">
SearchQuerySet().spatial(lat=45.15, lng=-93.85, d=3, sfield='loc', filter='bbox').order_by('geodist()')
</pre>
<p>To make this example work, we need to modify <code>haystack/backends/solr_backend.py</code> as follows, where we construct the Solr query finally.</p>
<pre class="brush: python; title: ; notranslate">
class SearchBackend(BaseSearchBackend):
    def search(self, query_string, sort_by=None, start_offset=0, end_offset=None,
               fields='', highlight=False, facets=None, date_facets=None, query_facets=None,
               narrow_queries=None, spelling_query=None,
               limit_to_registered_models=None, result_class=None,
               spatial_query=None, **kwargs):
        ...
        if spatial_query is not None:
            kwargs['pt'] = '%s,%s'%(spatial_query['lat'], spatial_query['lng'])
            kwargs['sfield'] = spatial_query['sfield']
            kwargs['d'] = spatial_query['d']
            if narrow_queries is None:
                narrow_queries = set()
            narrow_queries.add('{!%s}'% spatial_query['filter'])
        if narrow_queries is not None:
            kwargs['fq'] = list(narrow_queries)

class SearchQuery(BaseSearchQuery):
    def run(self, spelling_query=None):
        ...
        if self.spatial_query:
            kwargs['spatial_query'] = self.spatial_query
</pre>
<p>The final change we need to add is adding <code>SpatialError</code> in <code>haystack/exceptions.py</code>. The exception is used in the above code.</p>
<pre class="brush: python; title: ; notranslate">
class SpatialError(HaystackError):
    &quot;&quot;&quot;Raised when incorrect arguments have been provided for spatial.&quot;&quot;&quot;
    pass
</pre>
<p>All code changes in this blog can be found <a href="https://github.com/fuyun/django-haystack/tree/v1.2.5">here</a> on GitHub. It is based on Haystack v1.2.5.</p>
]]></content:encoded>
			<wfw:commentRss>http://fuyun.org/2011/11/add-solr-spatial-search-for-djang-haystack/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Weird Boot Error: virbr0 starting userspace STP failed</title>
		<link>http://fuyun.org/2010/02/weird-boot-error-virbr0-starting-userspace-stp-failed/</link>
		<comments>http://fuyun.org/2010/02/weird-boot-error-virbr0-starting-userspace-stp-failed/#comments</comments>
		<pubDate>Tue, 02 Feb 2010 06:58:07 +0000</pubDate>
		<dc:creator>yfu</dc:creator>
				<category><![CDATA[system]]></category>

		<guid isPermaLink="false">http://www.fuyun.org/?p=258</guid>
		<description><![CDATA[I suddenly could not boot my Linux box (Fedora 11) today. It showed some error messages as follows, In the beginning, I thought it is related to network or libvirtd. But I did not solve the problem by turning off &#8230; <a href="http://fuyun.org/2010/02/weird-boot-error-virbr0-starting-userspace-stp-failed/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I suddenly could not boot my Linux box (Fedora 11) today. It showed some error messages as follows,</p>
<pre class="brush: plain; title: ; notranslate">
virbr0: starting userspace STP failed, starting kernel STP
ADDRCONF(NETDEV_UP): eth0: link is not ready
e1000e: eth0 NIC Link is Up 100 Mbps Full Duplex, Flow Control: None
0000:00:19.0: eth0: 10/100 speed: disabling TSO
ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
</pre>
<p>In the beginning, I thought it is related to network or libvirtd. But I did not solve the problem by turning off libvirtd. I did not change anything in my last boot. But I updated Fedora packages using Software Update. However, I did not pay attention what I updated. By searching on web, I found some people talked about this issue after upgrading video drivers. I felt it may be the same reason.</p>
<p>My video card is Nvidia. I used nvidia linux driver (NVIDIA-Linux-x86-190.42-pkg1.run) downloaded from nvidia web site. To give it a try, I decided to reinstall it. So I boot at runlevel 3, and run the driver installer NVIDIA-Linux-x86-190.42-pkg1.run again in text mode. It rebuilt the driver and reset xorg.conf. Then, the problem was fixed.</p>
<p>After that, I found that there are actually a lot of errors in /var/log/Xorg.?.log such as</p>
<pre class="brush: plain; title: ; notranslate">
NVIDIA: Failed to load the NVIDIA kernel module. Please check
your system's kernel log for additional error messages.
</pre>
<p>Also, /var/log/messages log has error message as follows.</p>
<pre class="brush: plain; title: ; notranslate">
WARNING: GdmLocalDisplayFactory: maximum number of X display failures
reached: check X server log for errors
init:prefdm main process terminated with status 1
</pre>
<p>So this weird boot error is really caused by video driver. The errors related to virbr0 were just coincident errors that showed up after X failed to start. I checked my logs. Such errors have been there for every boot. I just did not see them. Now I turn off libvirtd service.</p>
<p>FYI, to boot into runlevel 3 in this hanging case. Select the linux image entry to boot in GRUB, press &#8216;e&#8217;.  In next screen, move to the kernel line, press &#8216;e&#8217;.  In my case, it ends up with &#8216;rhgb quiet&#8217;, which is redhat graphic boot. Delete &#8216;rhgb, quite&#8217;, replace it with &#8217;3&#8242;. Then press &#8216;b&#8217;. It will boot to runlevel 3 without starting those daemons or X window. Just log in as root and reinstall the video driver. If runlevel 3 does not work, try single user mode, i.e. replace &#8216;rhgb quite&#8217; with &#8216;single&#8217;.</p>
]]></content:encoded>
			<wfw:commentRss>http://fuyun.org/2010/02/weird-boot-error-virbr0-starting-userspace-stp-failed/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

