Hello list.

Please find attached, a proposal for geo distance search support of solr.

I'd like to point out a few issues I still see:

1) I figured altering the interface would be a bad idea, so I opted for
altering ezcSearchQuerySolr::eq() to handle distance search fields. This
is not extraordinarily pretty, but IMHO acceptable.

2) I added a struct for the search value, i.e. a geoposition (lat,lng)
and a distance (km). Search field and value are stored in the query
object in eq().

3) ezcSearchSolrHandler::find() extracts a number of values from $query
and passes them to search(). In order to add the geoposition search
field and values, I had to extend search() and buildQuery() by these
parameters. I wonder, why search() is not integrated into find() or
$query passed to search() as a whole.

4) I had to alter the $queryWord join() command in find() in order to
remove the NULL element present due to adding the geoposition search
field via eq().


Afterthought: It looks as if ezcSearchSolrHandler might be extended by
something like filterDistance($field, $value) without affecting the
interface, which should eleminate the flaws I pointed out in 1) and 4).


I would appreciate your comments and hints on oversights or problems.
Also tell me what I should do next if there is a chance to integrate the
geo distance search functionality to ezcSearch. Thanks.

Best regards,
  David

-- 
David Rekowski
mailto:david.rekow...@gmx.de

Index: handlers/solr.php
===================================================================
--- handlers/solr.php   (revision 1180804)
+++ handlers/solr.php   (working copy)
@@ -340,7 +340,7 @@
      * @param array(string=>string) $order
      * @return array
      */
-    private function buildQuery( $queryWord, $defaultField, $searchFieldList = 
array(), $returnFieldList = array(), $highlightFieldList = array(), 
$facetFieldList = array(), $limit = null, $offset = false, $order = array() )
+    private function buildQuery( $queryWord, $defaultField, $searchFieldList = 
array(), $returnFieldList = array(), $highlightFieldList = array(), 
$facetFieldList = array(), $limit = null, $offset = false, $order = array(), 
$distanceField = '', $geoDistance = 0 )
     {
         if ( count( $searchFieldList ) > 0 )
         {
@@ -359,6 +359,13 @@
         $returnFieldList[] = 'score';
         $queryFlags['fl'] = join( ' ', $returnFieldList );
 
+        if ($distanceField != '') {
+            $queryFlags['fq'] = '{!geofilt}';
+            $queryFlags['pt'] = $geoDistance->lat.','.$geoDistance->lng;
+            $queryFlags['d'] = $geoDistance->distance;
+            $queryFlags['sfield'] = $distanceField;
+        }
+
         if ( count( $highlightFieldList ) )
         {
             $queryFlags['hl'] = 'true';
@@ -510,9 +517,9 @@
      * @param array(string=>string) $order
      * @return stdClass
      */
-    public function search( $queryWord, $defaultField, $searchFieldList = 
array(), $returnFieldList = array(), $highlightFieldList = array(), 
$facetFieldList = array(), $limit = null, $offset = 0, $order = array() )
+    public function search( $queryWord, $defaultField, $searchFieldList = 
array(), $returnFieldList = array(), $highlightFieldList = array(), 
$facetFieldList = array(), $limit = null, $offset = 0, $order = array(), 
$distanceField = '', $geoDistance = 0 )
     {
-        $result = $this->sendRawGetCommand( 'select', $this->buildQuery( 
$queryWord, $defaultField, $searchFieldList, $returnFieldList, 
$highlightFieldList, $facetFieldList, $limit, $offset, $order ) );
+        $result = $this->sendRawGetCommand( 'select', $this->buildQuery( 
$queryWord, $defaultField, $searchFieldList, $returnFieldList, 
$highlightFieldList, $facetFieldList, $limit, $offset, $order, $distanceField, 
$geoDistance ) );
         if ( ( $data = json_decode( $result ) ) === null )
         {
             throw new ezcSearchInvalidResultException( $result );
@@ -568,15 +575,17 @@
      */
     public function find( ezcSearchFindQuery $query )
     {
-        $queryWord = join( ' AND ', $query->whereClauses );
+        $queryWord = join( ' AND ', array_diff($query->whereClauses, 
array(NULL)));
         $resultFieldList = $query->resultFields;
         $highlightFieldList = $query->highlightFields;
         $facetFieldList = $query->facets;
         $limit = $query->limit;
         $offset = $query->offset;
         $order = $query->orderByClauses;
+        $geoDistanceField = $query->geoDistanceField;
+        $geoDistanceValue = $query->geoDistanceValue;
 
-        $res = $this->search( $queryWord, '', array(), $resultFieldList, 
$highlightFieldList, $facetFieldList, $limit, $offset, $order );
+        $res = $this->search( $queryWord, '', array(), $resultFieldList, 
$highlightFieldList, $facetFieldList, $limit, $offset, $order, 
$geoDistanceField, $geoDistanceValue );
         return $this->createResponseFromData( $query->getDefinition(), $res );
     }
 
Index: abstraction/implementations/solr.php
===================================================================
--- abstraction/implementations/solr.php        (revision 1180804)
+++ abstraction/implementations/solr.php        (working copy)
@@ -278,14 +278,19 @@
 
         $this->checkIfFieldExists( $field );
         $fieldType = $this->definition->fields[$field]->type;
-        $value = $this->handler->mapFieldValueForSearch( $fieldType, $value );
-        $fieldName = $this->handler->mapFieldType( $field, 
$this->definition->fields[$field]->type );
-
-        $ret = "$fieldName:$value";
-
-        if ( $this->definition->fields[$field]->boost != 1 )
-        {
-            $ret .= "^{$this->definition->fields[$field]->boost}";
+        if ($fieldType == ezcSearchDocumentDefinition::GEOPOSITION) {
+            $this->geoDistanceField = $field;
+            $this->geoDistanceValue = $value;
+        } else {
+            $value = $this->handler->mapFieldValueForSearch( $fieldType, 
$value );
+            $fieldName = $this->handler->mapFieldType( $field, 
$this->definition->fields[$field]->type );
+
+            $ret = "$fieldName:$value";
+
+            if ( $this->definition->fields[$field]->boost != 1 )
+            {
+                $ret .= "^{$this->definition->fields[$field]->boost}";
+            }
         }
         return $ret;
     }
Index: document_definition.php
===================================================================
--- document_definition.php     (revision 1180804)
+++ document_definition.php     (working copy)
@@ -51,6 +51,8 @@
      */
     const BOOLEAN = 7;
 
+    const GEOPOSITION = 8;
+
     /**
      * Contains the document type - which is the same as the class name.
      *
<?php

class ezcSearchSolrGeoDistance {

  public $lat = 0.0;
  public $lng = 0.0;
  public $distance = 10;

  public function __construct($lat, $lng, $distance) {
    $this->lat = $lat;
    $this->lng = $lng;
    $this->distance = $distance;
  }
}

Reply via email to