Author: ahorincar
Date: Wed Aug 13 16:08:04 2014
New Revision: 1617747
URL: http://svn.apache.org/r1617747
Log:
Finished More Like This feature, formatted code, refactored code
Added:
bloodhound/branches/bep_0014_solr/bloodhound_solr/README
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/solr_backend.py
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/tests/
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/tests/__init__.py
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/tests/backend.py
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/tests/schema.py
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/tests/search_resources/
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/tests/search_resources/__init__.py
bloodhound/branches/bep_0014_solr/bloodhound_theme/bhtheme/templates/bh_more_like_this.html
Removed:
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/backend.py
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/schemadoc/
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/web_ui.py
Modified:
bloodhound/branches/bep_0014_solr/bloodhound_search/bhsearch/api.py
bloodhound/branches/bep_0014_solr/bloodhound_search/bhsearch/templates/bhsearch.html
bloodhound/branches/bep_0014_solr/bloodhound_search/bhsearch/web_ui.py
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/__init__.py
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/admin.py
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/schema.py
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/__init__.py
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/changeset_search.py
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/milestone_search.py
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/ticket_search.py
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/wiki_search.py
bloodhound/branches/bep_0014_solr/bloodhound_solr/setup.py
bloodhound/branches/bep_0014_solr/bloodhound_theme/bhtheme/theme.py
Modified: bloodhound/branches/bep_0014_solr/bloodhound_search/bhsearch/api.py
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0014_solr/bloodhound_search/bhsearch/api.py?rev=1617747&r1=1617746&r2=1617747&view=diff
==============================================================================
--- bloodhound/branches/bep_0014_solr/bloodhound_search/bhsearch/api.py
(original)
+++ bloodhound/branches/bep_0014_solr/bloodhound_search/bhsearch/api.py Wed Aug
13 16:08:04 2014
@@ -319,13 +319,20 @@ class BloodhoundSearchApi(Component):
for query_processor in self.query_processors:
query_processor.query_pre_process(query_parameters, context)
- query_result = self.backend.query(**query_parameters)
+ # Compatibility with both Solr and Whoosh backends.
+ mlt = None
+ hexdigests = None
+
+ if self.backend.__class__.__name__ == 'SolrBackend':
+ query_result, mlt, hexdigests =
self.backend.query(**query_parameters)
+ else:
+ query_result = self.backend.query(**query_parameters)
for post_processor in self.result_post_processors:
post_processor.post_process(query_result)
query_result.debug["api_parameters"] = query_parameters
- return query_result
+ return query_result, mlt, hexdigests
def start_operation(self):
return self.backend.start_operation()
Modified:
bloodhound/branches/bep_0014_solr/bloodhound_search/bhsearch/templates/bhsearch.html
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0014_solr/bloodhound_search/bhsearch/templates/bhsearch.html?rev=1617747&r1=1617746&r2=1617747&view=diff
==============================================================================
---
bloodhound/branches/bep_0014_solr/bloodhound_search/bhsearch/templates/bhsearch.html
(original)
+++
bloodhound/branches/bep_0014_solr/bloodhound_search/bhsearch/templates/bhsearch.html
Wed Aug 13 16:08:04 2014
@@ -166,6 +166,10 @@
<py:if test="result.author"><span class="author"
i18n:msg="author">By ${format_author(result.author)}</span> —</py:if>
<span class="date">${result.date}</span>
</dd>
+ <!-- Include the template that displays More Like This
results for each result (only for when Solr backend is being used, not Whoosh).
-->
+ <dd py:if="mlt and hexdigests">
+ <xi:include py:with="doc = result; doc_mlt =
mlt[result.unique_id]; hexdigest = hexdigests[result.unique_id];"
href="bh_more_like_this.html" />
+ </dd>
</py:for>
</dl>
</py:if>
Modified: bloodhound/branches/bep_0014_solr/bloodhound_search/bhsearch/web_ui.py
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0014_solr/bloodhound_search/bhsearch/web_ui.py?rev=1617747&r1=1617746&r2=1617747&view=diff
==============================================================================
--- bloodhound/branches/bep_0014_solr/bloodhound_search/bhsearch/web_ui.py
(original)
+++ bloodhound/branches/bep_0014_solr/bloodhound_search/bhsearch/web_ui.py Wed
Aug 13 16:08:04 2014
@@ -338,7 +338,7 @@ class BloodhoundSearchModule(Component):
# compatibility with legacy search
req.search_query = request_context.parameters.query
- query_result = BloodhoundSearchApi(self.env).query(
+ query_result, mlt, hexdigests = BloodhoundSearchApi(self.env).query(
request_context.parameters.query,
pagenum=request_context.page,
pagelen=request_context.pagelen,
@@ -350,6 +350,11 @@ class BloodhoundSearchModule(Component):
context=request_context,
)
+ # Needed for showing More Like This results in Genshi
+ # templates.
+ request_context.data['mlt'] = mlt
+ request_context.data['hexdigests'] = hexdigests
+
request_context.process_results(query_result)
return self._return_data(req, request_context.data)
Added: bloodhound/branches/bep_0014_solr/bloodhound_solr/README
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0014_solr/bloodhound_solr/README?rev=1617747&view=auto
==============================================================================
--- bloodhound/branches/bep_0014_solr/bloodhound_solr/README (added)
+++ bloodhound/branches/bep_0014_solr/bloodhound_solr/README Wed Aug 13
16:08:04 2014
@@ -0,0 +1,29 @@
+= Plugin to add Apache Solr as a search alternative for Apache Bloodhound =
+
+== Description ==
+
+The plugin enhances Apache Bloodhound with Apache Solr functionality, namely
+it allows using Apache Solr as a search alternative.
+
+== Dependencies ==
+
+This plugin depends on the following components to be installed:
+
+ - [http:trac.edgewall.org Trac] ,,Since version ''' 1.0 ''',, .
+ - [http://lucene.apache.org/solr/index.html Apache Solr] ,,Version ''' 4.7.2
''',, .
+ - [http://lxml.de/ Lxml]
+ - [https://github.com/tow/sunburnt Sunburnt] ,,Since version '''0.6''',, .
+ - [https://code.google.com/p/httplib2/ Httplib2]
+
+
+== Latest Version ==
+
+
+== Installation ==
+
+
+== Licensing ==
+
+
+== Contacts ==
+
Modified: bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/__init__.py
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/__init__.py?rev=1617747&r1=1617746&r2=1617747&view=diff
==============================================================================
--- bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/__init__.py
(original)
+++ bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/__init__.py Wed
Aug 13 16:08:04 2014
@@ -0,0 +1,18 @@
+# -*- coding: UTF-8 -*-
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
Modified: bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/admin.py
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/admin.py?rev=1617747&r1=1617746&r2=1617747&view=diff
==============================================================================
--- bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/admin.py (original)
+++ bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/admin.py Wed Aug
13 16:08:04 2014
@@ -1,6 +1,25 @@
+# -*- coding: UTF-8 -*-
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
from trac.core import Component, implements
-from bhsolr.schema import SolrSchema
from trac.admin import IAdminCommandProvider
+from bhsolr.schema import SolrSchema
class BloodhoundSolrAdmin(Component):
Modified: bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/schema.py
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/schema.py?rev=1617747&r1=1617746&r2=1617747&view=diff
==============================================================================
--- bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/schema.py
(original)
+++ bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/schema.py Wed Aug
13 16:08:04 2014
@@ -1,169 +1,198 @@
+# -*- coding: UTF-8 -*-
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import os
+
from lxml import etree
-from bhsearch.whoosh_backend import WhooshBackend
+
from trac.core import Component, implements, TracError
-import os
+from bhsearch.whoosh_backend import WhooshBackend
+from bhsolr.solr_backend import SolrBackend
class SolrSchema(Component):
- instance = None
- REQUIRED_FIELDS = {"id": True,
- "unique_id": True,
- "type": True}
-
- FIELDS_TYPE_DICT = {"ID": "string",
- "DATETIME": "date",
- "KEYWORD": "string",
- "TEXT": "text_general"
- }
-
- def __init__(self):
- self.schema = WhooshBackend.SCHEMA
- self.schema_element = etree.Element("schema")
- self.schema_element.set("name", "Bloodhound Solr Schema")
- self.schema_element.set("version", "1")
-
- self.path = None
- self.fields_element = etree.SubElement(self.schema_element, "fields")
- self.unique_key_element = etree.SubElement(self.schema_element,
"uniqueKey")
- self.unique_key_element.text = "unique_id"
-
- version_field = etree.SubElement(self.fields_element, "field")
- version_field.set("name", "_version_")
- version_field.set("type", "long")
- version_field.set("indexed", "true")
- version_field.set("stored", "true")
-
- root_field = etree.SubElement(self.fields_element, "field")
- root_field.set("name", "_root_")
- root_field.set("type", "string")
- root_field.set("indexed", "true")
- root_field.set("stored", "false")
-
- stored_name = etree.SubElement(self.fields_element, "field")
- stored_name.set("name", "_stored_name")
- stored_name.set("type", "string")
- stored_name.set("indexed", "true")
- stored_name.set("stored", "true")
- stored_name.set("required", "false")
- stored_name.set("multivalued", "false")
-
- # @classmethod
- # def getInstance(self, env):
- # if not self.instance:
- # self.instance = SolrSchema(env)
- # return self.instance
-
- def generate_schema(self, path=None):
- if not path:
- path = os.getcwd()
-
- self.add_all_fields()
- self.add_type_definitions()
- doc = etree.ElementTree(self.schema_element)
-
- self.path = os.path.join(path, 'schema.xml')
-
- out_file = open(os.path.join(path, 'schema.xml'), 'w')
- doc.write(out_file, xml_declaration=True, encoding='UTF-8',
pretty_print=True)
- out_file.close()
-
- def add_field(self, field_name, name_attr, type_attr, indexed_attr,
stored_attr, required_attr, multivalued_attr):
- field = etree.SubElement(self.fields_element, field_name)
- field.set("name", name_attr)
- field.set("type", type_attr)
- field.set("indexed", indexed_attr)
- field.set("stored", stored_attr)
- field.set("required", required_attr)
- field.set("multivalued", multivalued_attr)
-
- def add_all_fields(self):
- for (field_name, field_attrs) in self.schema.items():
- type_attr =
SolrSchema.FIELDS_TYPE_DICT[str(field_attrs.__class__.__name__)]
- indexed_attr = str(field_attrs.indexed).lower()
- stored_attr = str(field_attrs.stored).lower()
- if field_name in SolrSchema.REQUIRED_FIELDS:
- required_attr = "true"
- else:
- required_attr = "false"
-
- self.add_field("field", field_name, type_attr, indexed_attr,
stored_attr, required_attr, "false")
-
-
- def add_type_definitions(self):
- self.types_element = etree.SubElement(self.schema_element, "types")
- self._add_string_type_definition()
- self._add_text_general_type_definition()
- self._add_date_type_definition()
- self._add_long_type_definition()
- self._add_lowercase_type_definition()
-
-
- def _add_string_type_definition(self):
- field_type = etree.SubElement(self.types_element, "fieldType")
- field_type.set("name", "string")
- field_type.set("class", "solr.StrField")
- field_type.set("sortMissingLast", "true")
-
-
- def _add_text_general_type_definition(self):
- field_type = etree.SubElement(self.types_element, "fieldType")
- field_type.set("name", "text_general")
- field_type.set("class", "solr.TextField")
- field_type.set("positionIncrementGap", "100")
-
- analyzer_index = etree.SubElement(field_type, "analyzer")
- analyzer_index.set("type", "index")
-
- tokenizer_index = etree.SubElement(analyzer_index, "tokenizer")
- tokenizer_index.set("class", "solr.StandardTokenizerFactory")
- filter1 = etree.SubElement(analyzer_index, "filter")
- filter1.set("class", "solr.StopFilterFactory")
- filter1.set("ignoreCase", "true")
- filter1.set("words", "stopwords.txt")
-
- filter2 = etree.SubElement(analyzer_index, "filter")
- filter2.set("class", "solr.LowerCaseFilterFactory")
-
- analyzer_query = etree.SubElement(field_type, "analyzer")
- analyzer_query.set("type", "query")
- tokenizer_query = etree.SubElement(analyzer_query, "tokenizer")
- tokenizer_query.set("class", "solr.StandardTokenizerFactory")
- filter3 = etree.SubElement(analyzer_query, "filter")
- filter3.set("class", "solr.StopFilterFactory")
- filter3.set("ignoreCase", "true")
- filter3.set("words", "stopwords.txt")
-
- filter4 = etree.SubElement(analyzer_query, "filter")
- filter4.set("class", "solr.SynonymFilterFactory")
- filter4.set("synonyms", "synonyms.txt")
- filter4.set("ignoreCase", "true")
- filter4.set("expand", "true")
-
- filter5 = etree.SubElement(analyzer_query, "filter")
- filter5.set("class", "solr.LowerCaseFilterFactory")
-
- def _add_date_type_definition(self):
- field_type = etree.SubElement(self.types_element, "fieldType")
- field_type.set("name", "date")
- field_type.set("class", "solr.TrieDateField")
- field_type.set("precisionStep", "0")
- field_type.set("positionIncrementGap", "0")
-
- def _add_long_type_definition(self):
- field_type = etree.SubElement(self.types_element, "fieldType")
- field_type.set("name", "long")
- field_type.set("class", "solr.TrieLongField")
- field_type.set("precisionStep", "0")
- field_type.set("positionIncrementGap", "0")
-
- def _add_lowercase_type_definition(self):
- field_type = etree.SubElement(self.types_element, "fieldType")
- field_type.set("name", "lowercase")
- field_type.set("class", "solr.TextField")
- field_type.set("positionIncrementGap", "100")
-
- analyzer = etree.SubElement(field_type, "analyzer")
- tokenizer = etree.SubElement(analyzer, "tokenizer")
- tokenizer.set("class", "solr.KeywordTokenizerFactory")
- filter_lowercase = etree.SubElement(analyzer, "filter")
- filter_lowercase.set("class", "solr.LowerCaseFilterFactory")
+ REQUIRED_FIELDS = {
+ "id": True,
+ "unique_id": True,
+ "type": True
+ }
+
+ FIELDS_TYPE_DICT = {
+ "ID": "string",
+ "DATETIME": "date",
+ "KEYWORD": "string",
+ "TEXT": "text_general"
+ }
+
+ def __init__(self):
+ self.path = None
+ self.schema = WhooshBackend.SCHEMA
+ self.schema_element = etree.Element("schema")
+ self.schema_element.set("name", "Bloodhound Solr Schema")
+ self.schema_element.set("version", "1")
+
+ self.fields_element = etree.SubElement(self.schema_element, "fields")
+
+ self.unique_key_element = etree.SubElement(self.schema_element,
+ "uniqueKey")
+ self.unique_key_element.text = SolrBackend.UNIQUE_ID
+
+ version_field = etree.SubElement(self.fields_element, "field")
+ version_field.set("name", "_version_")
+ version_field.set("type", "long")
+ version_field.set("indexed", "true")
+ version_field.set("stored", "true")
+ version_field.set("multiValued", "false")
+
+ root_field = etree.SubElement(self.fields_element, "field")
+ root_field.set("name", "_root_")
+ root_field.set("type", "string")
+ root_field.set("indexed", "true")
+ root_field.set("stored", "false")
+
+ stored_name = etree.SubElement(self.fields_element, "field")
+ stored_name.set("name", "_stored_name")
+ stored_name.set("type", "string")
+ stored_name.set("indexed", "true")
+ stored_name.set("stored", "true")
+ stored_name.set("required", "false")
+ stored_name.set("multiValued", "false")
+
+ def generate_schema(self, path=None):
+ if not path:
+ path = os.getcwd()
+ self.path = os.path.join(path, 'schema.xml')
+
+ self.add_all_fields()
+ self.add_type_definitions()
+
+ doc = etree.ElementTree(self.schema_element)
+ out_file = open(os.path.join(path, 'schema.xml'), 'w')
+ doc.write(out_file, xml_declaration=True, encoding='UTF-8',
+ pretty_print=True)
+ out_file.close()
+
+ def add_field(
+ self, field_name, name_attr, type_attr, indexed_attr,
+ stored_attr, required_attr, multivalued_attr):
+ field = etree.SubElement(self.fields_element, field_name)
+ field.set("name", name_attr)
+ field.set("type", type_attr)
+ field.set("indexed", indexed_attr)
+ field.set("stored", stored_attr)
+ field.set("required", required_attr)
+ field.set("multiValued", multivalued_attr)
+
+ def add_all_fields(self):
+ for (field_name, field_attrs) in self.schema.items():
+ class_name = str(field_attrs.__class__.__name__)
+ type_attr = self.FIELDS_TYPE_DICT[class_name]
+ indexed_attr = str(field_attrs.indexed).lower()
+ stored_attr = str(field_attrs.stored).lower()
+
+ if field_name in self.REQUIRED_FIELDS:
+ required_attr = "true"
+ else:
+ required_attr = "false"
+
+ self.add_field("field", field_name, type_attr, indexed_attr,
+ stored_attr, required_attr, "false")
+
+ def add_type_definitions(self):
+ self.types_element = etree.SubElement(self.schema_element, "types")
+ self._add_string_type_definition()
+ self._add_text_general_type_definition()
+ self._add_date_type_definition()
+ self._add_long_type_definition()
+ self._add_lowercase_type_definition()
+
+ def _add_string_type_definition(self):
+ field_type = etree.SubElement(self.types_element, "fieldType")
+ field_type.set("name", "string")
+ field_type.set("class", "solr.StrField")
+ field_type.set("sortMissingLast", "true")
+
+ def _add_text_general_type_definition(self):
+ field_type = etree.SubElement(self.types_element, "fieldType")
+ field_type.set("name", "text_general")
+ field_type.set("class", "solr.TextField")
+ field_type.set("positionIncrementGap", "100")
+
+ analyzer_index = etree.SubElement(field_type, "analyzer")
+ analyzer_index.set("type", "index")
+
+ tokenizer_index = etree.SubElement(analyzer_index, "tokenizer")
+ tokenizer_index.set("class", "solr.StandardTokenizerFactory")
+
+ analyzer_index_filter_s = etree.SubElement(analyzer_index, "filter")
+ analyzer_index_filter_s.set("class", "solr.StopFilterFactory")
+ analyzer_index_filter_s.set("ignoreCase", "true")
+ analyzer_index_filter_s.set("words", "stopwords.txt")
+
+ analyzer_index_filter_l = etree.SubElement(analyzer_index, "filter")
+ analyzer_index_filter_l.set("class", "solr.LowerCaseFilterFactory")
+
+ analyzer_query = etree.SubElement(field_type, "analyzer")
+ analyzer_query.set("type", "query")
+
+ tokenizer_query = etree.SubElement(analyzer_query, "tokenizer")
+ tokenizer_query.set("class", "solr.StandardTokenizerFactory")
+
+ analyzer_query_filter_s = etree.SubElement(analyzer_query, "filter")
+ analyzer_query_filter_s.set("class", "solr.StopFilterFactory")
+ analyzer_query_filter_s.set("ignoreCase", "true")
+ analyzer_query_filter_s.set("words", "stopwords.txt")
+
+ analyzer_query_filter_syn = etree.SubElement(analyzer_query, "filter")
+ analyzer_query_filter_syn.set("class", "solr.SynonymFilterFactory")
+ analyzer_query_filter_syn.set("synonyms", "synonyms.txt")
+ analyzer_query_filter_syn.set("ignoreCase", "true")
+ analyzer_query_filter_syn.set("expand", "true")
+
+ analyzer_query_filter_l = etree.SubElement(analyzer_query, "filter")
+ analyzer_query_filter_l.set("class", "solr.LowerCaseFilterFactory")
+
+ def _add_date_type_definition(self):
+ field_type = etree.SubElement(self.types_element, "fieldType")
+ field_type.set("name", "date")
+ field_type.set("class", "solr.TrieDateField")
+ field_type.set("precisionStep", "0")
+ field_type.set("positionIncrementGap", "0")
+
+ def _add_long_type_definition(self):
+ field_type = etree.SubElement(self.types_element, "fieldType")
+ field_type.set("name", "long")
+ field_type.set("class", "solr.TrieLongField")
+ field_type.set("precisionStep", "0")
+ field_type.set("positionIncrementGap", "0")
+
+ def _add_lowercase_type_definition(self):
+ field_type = etree.SubElement(self.types_element, "fieldType")
+ field_type.set("name", "lowercase")
+ field_type.set("class", "solr.TextField")
+ field_type.set("positionIncrementGap", "100")
+
+ analyzer = etree.SubElement(field_type, "analyzer")
+
+ tokenizer = etree.SubElement(analyzer, "tokenizer")
+ tokenizer.set("class", "solr.KeywordTokenizerFactory")
+
+ analyzer_filter_l = etree.SubElement(analyzer, "filter")
+ analyzer_filter_l.set("class", "solr.LowerCaseFilterFactory")
+
Modified:
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/__init__.py
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/__init__.py?rev=1617747&r1=1617746&r2=1617747&view=diff
==============================================================================
---
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/__init__.py
(original)
+++
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/__init__.py
Wed Aug 13 16:08:04 2014
@@ -0,0 +1,18 @@
+# -*- coding: UTF-8 -*-
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
Modified:
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/changeset_search.py
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/changeset_search.py?rev=1617747&r1=1617746&r2=1617747&view=diff
==============================================================================
---
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/changeset_search.py
(original)
+++
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/changeset_search.py
Wed Aug 13 16:08:04 2014
@@ -1,17 +1,36 @@
-from bhsearch.search_resources.base import BaseIndexer
+# -*- coding: UTF-8 -*-
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
from trac.versioncontrol.api import RepositoryManager
+from bhsearch.search_resources.base import BaseIndexer
from bhsearch.search_resources.changeset_search import ChangesetIndexer
class ChangesetSearchModel(BaseIndexer):
- def get_entries_for_index(self):
- repository_manager = RepositoryManager(self.env)
- for repository in repository_manager.get_real_repositories():
- rev = repository.oldest_rev
- stop = repository.youngest_rev
- while True:
- changeset = repository.get_changeset(rev)
- yield ChangesetIndexer(self.env).build_doc(changeset)
- if rev == stop:
- break
- rev = repository.next_rev(rev)
+ def get_entries_for_index(self):
+ repository_manager = RepositoryManager(self.env)
+ for repository in repository_manager.get_real_repositories():
+ rev = repository.oldest_rev
+ stop = repository.youngest_rev
+ while True:
+ changeset = repository.get_changeset(rev)
+ yield ChangesetIndexer(self.env).build_doc(changeset)
+ if rev == stop:
+ break
+ rev = repository.next_rev(rev)
Modified:
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/milestone_search.py
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/milestone_search.py?rev=1617747&r1=1617746&r2=1617747&view=diff
==============================================================================
---
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/milestone_search.py
(original)
+++
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/milestone_search.py
Wed Aug 13 16:08:04 2014
@@ -1,9 +1,28 @@
-from bhsearch.search_resources.base import BaseIndexer
+# -*- coding: UTF-8 -*-
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
from trac.ticket import Milestone
+from bhsearch.search_resources.base import BaseIndexer
from bhsearch.search_resources.milestone_search import MilestoneIndexer
class MilestoneSearchModel(BaseIndexer):
- def get_entries_for_index(self):
- for milestone in Milestone.select(self.env, include_completed=True):
- yield MilestoneIndexer(self.env).build_doc(milestone)
+ def get_entries_for_index(self):
+ for milestone in Milestone.select(self.env, include_completed=True):
+ yield MilestoneIndexer(self.env).build_doc(milestone)
Modified:
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/ticket_search.py
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/ticket_search.py?rev=1617747&r1=1617746&r2=1617747&view=diff
==============================================================================
---
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/ticket_search.py
(original)
+++
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/ticket_search.py
Wed Aug 13 16:08:04 2014
@@ -1,27 +1,46 @@
+# -*- coding: UTF-8 -*-
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
from trac.ticket.model import Ticket
-from bhsearch.search_resources.ticket_search import TicketIndexer
from trac.core import Component, implements, TracError
+from bhsearch.search_resources.ticket_search import TicketIndexer
from bhsearch.search_resources.base import BaseIndexer
class TicketSearchModel(BaseIndexer):
- def _fetch_tickets(self, **kwargs):
- for ticket_id in self._fetch_ids(**kwargs):
- yield Ticket(self.env, ticket_id)
-
- def _fetch_ids(self, **kwargs):
- sql = "SELECT id FROM ticket"
- args = []
- conditions = []
- for key, value in kwargs.iteritems():
- args.append(value)
- conditions.append(key + "=%s")
- if conditions:
- sql = sql + " WHERE " + " AND ".join(conditions)
- for row in self.env.db_query(sql, args):
- yield int(row[0])
-
- def get_entries_for_index(self):
- for ticket in self._fetch_tickets():
- yield TicketIndexer(self.env).build_doc(ticket)
+ def _fetch_tickets(self, **kwargs):
+ for ticket_id in self._fetch_ids(**kwargs):
+ yield Ticket(self.env, ticket_id)
+
+ def _fetch_ids(self, **kwargs):
+ sql = "SELECT id FROM ticket"
+ args = []
+ conditions = []
+ for key, value in kwargs.iteritems():
+ args.append(value)
+ conditions.append(key + "=%s")
+ if conditions:
+ sql = sql + " WHERE " + " AND ".join(conditions)
+ for row in self.env.db_query(sql, args):
+ yield int(row[0])
+
+ def get_entries_for_index(self):
+ for ticket in self._fetch_tickets():
+ yield TicketIndexer(self.env).build_doc(ticket)
Modified:
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/wiki_search.py
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/wiki_search.py?rev=1617747&r1=1617746&r2=1617747&view=diff
==============================================================================
---
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/wiki_search.py
(original)
+++
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/search_resources/wiki_search.py
Wed Aug 13 16:08:04 2014
@@ -1,11 +1,30 @@
+# -*- coding: UTF-8 -*-
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
from trac.wiki import WikiSystem, WikiPage
from bhsearch.search_resources.wiki_search import WikiIndexer
from bhsearch.search_resources.base import BaseIndexer
class WikiSearchModel(BaseIndexer):
- def get_entries_for_index(self):
- page_names = WikiSystem(self.env).get_pages()
- for page_name in page_names:
- page = WikiPage(self.env, page_name)
- yield WikiIndexer(self.env).build_doc(page)
+ def get_entries_for_index(self):
+ page_names = WikiSystem(self.env).get_pages()
+ for page_name in page_names:
+ page = WikiPage(self.env, page_name)
+ yield WikiIndexer(self.env).build_doc(page)
Added: bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/solr_backend.py
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/solr_backend.py?rev=1617747&view=auto
==============================================================================
--- bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/solr_backend.py
(added)
+++ bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/solr_backend.py
Wed Aug 13 16:08:04 2014
@@ -0,0 +1,276 @@
+# -*- coding: UTF-8 -*-
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import re
+import hashlib
+
+from math import ceil
+from datetime import datetime
+from contextlib import contextmanager
+from sunburnt import SolrInterface
+
+from bhsearch import BHSEARCH_CONFIG_SECTION
+from bhsearch.api import ISearchBackend, SCORE, QueryResult
+from bhsearch.query_parser import DefaultQueryParser
+from bhsearch.search_resources.ticket_search import TicketIndexer
+from multiproduct.env import ProductEnvironment
+from trac.core import Component, implements, TracError
+from trac.config import Option
+from trac.ticket.model import Ticket
+from trac.ticket.api import TicketSystem
+from trac.util.datefmt import utc
+
+
+class SolrBackend(Component):
+ implements(ISearchBackend)
+
+ UNIQUE_ID = "unique_id"
+
+ HIGHLIGHTABLE_FIELDS = {
+ "unique_id" : True,
+ "id" : True,
+ "type" : True,
+ "product" : True,
+ "milestone" : True,
+ "author" : True,
+ "component" : True,
+ "status" : True,
+ "resolution" : True,
+ "keywords" : True,
+ "summary" : True,
+ "content" : True,
+ "changes" : True,
+ "owner" : True,
+ "repository" : True,
+ "revision" : True,
+ "message" : True,
+ "name" : True
+ }
+
+ server_url = Option(
+ BHSEARCH_CONFIG_SECTION,
+ 'solr_server_url',
+ doc="""Url of the server running Solr instance.""",
+ doc_domain='bhsearch')
+
+ def __init__(self):
+ self.solr_interface = SolrInterface(str(self.server_url))
+
+ def add_doc(self, doc, operation_context=None):
+ self._reformat_doc(doc)
+ doc[self.UNIQUE_ID] = self._create_unique_id(doc.get("product", ''),
+ doc["type"], doc["id"])
+ self.solr_interface.add(doc)
+ self.solr_interface.commit()
+
+ def delete_doc(product, doc_type, doc_id, operation_context=None):
+ unique_id = self._create_unique_id(product, doc_type, doc_id)
+ self.solr_interface.delete(unique_id)
+
+ def optimize(self):
+ self.solr_interface.optimize()
+
+ def query(
+ self, query, query_string, sort = None, fields = None,
+ filter = None, facets = None, pagenum = 1, pagelen = 20,
+ highlight = False, highlight_fields = None, context = None):
+
+ if not query_string:
+ query_string = "*.*"
+
+ final_query_chain = self._create_query_chain(query, query_string)
+ solr_query = self.solr_interface.query(final_query_chain)
+ faceted_solr_query = solr_query.facet_by(facets)
+ highlighted_solr_query = faceted_solr_query.highlight(
+ self.HIGHLIGHTABLE_FIELDS)
+
+ start = 0 if pagenum == 1 else pagelen * pagenum
+ paginated_solr_query = highlighted_solr_query.paginate(
+ start=start, rows=pagelen)
+ results = paginated_solr_query.execute()
+
+ mlt, hexdigests = self.query_more_like_this(paginated_solr_query,
+ fields="type", mindf=1,
+ mintf=1)
+
+ query_result = self._create_query_result(highlighted_solr_query,
+ results, fields, pagenum,
+ pagelen)
+ return query_result, mlt, hexdigests
+
+ def query_more_like_this(self, query_chain, **kwargs):
+ mlt_results = query_chain.mlt(**kwargs).execute().more_like_these
+ mlt_dict = {}
+ hexdigests = {}
+
+ for doc, results in mlt_results.iteritems():
+ hexdigest = hashlib.md5(doc).hexdigest()
+ hexdigests[doc] = hexdigest
+
+ for mlt_doc in results.docs:
+ if doc not in mlt_dict:
+ mlt_dict[doc] = [self._process_doc(mlt_doc)]
+ else:
+ mlt_dict[doc].append(self._process_doc(mlt_doc))
+
+ return mlt_dict, hexdigests
+
+ def _process_doc(self, doc):
+ ui_doc = dict(doc)
+
+ if doc.get('product'):
+ env = ProductEnvironment(self.env, doc['product'])
+ product_href = ProductEnvironment.resolve_href(env, self.env)
+ ui_doc["href"] = product_href(doc['type'], doc['id'])
+ else:
+ ui_doc["href"] = self.env.href(doc['type'], doc['id'])
+
+ ui_doc['title'] = str(doc['type'] + ": " + doc['_stored_name']).title()
+
+ return ui_doc
+
+ def _create_query_result(
+ self, query, results, fields, pagenum, pagelen):
+ total_num, total_page_count, page_num, offset = \
+ self._prepare_query_result_attributes(query, results,
+ pagenum, pagelen)
+
+ query_results = QueryResult()
+ query_results.hits = total_num
+ query_results.total_page_count = total_page_count
+ query_results.page_number = page_num
+ query_results.offset = offset
+
+ docs = []
+ highlighting = []
+
+ for retrieved_record in results:
+ result_doc = self._process_record(fields, retrieved_record)
+ docs.append(result_doc)
+
+ result_highlights = dict(retrieved_record['solr_highlights'])
+
+ highlighting.append(result_highlights)
+ query_results.docs = docs
+ query_results.highlighting = highlighting
+
+ return query_results
+
+ def _create_query_chain(self, query, query_string):
+ matches = re.findall(re.compile(r'([\w\*]+)'), query_string)
+ tokens = set([match for match in matches])
+
+ final_query_chain = None
+ for token in tokens:
+ token_query_chain = self._search_fields_for_token(token)
+ if final_query_chain is None:
+ final_query_chain = token_query_chain
+ else:
+ final_query_chain |= token_query_chain
+
+ return final_query_chain
+
+ def _process_record(self, fields, retrieved_record):
+ result_doc = dict()
+ if fields:
+ for field in fields:
+ if field in retrieved_record:
+ result_doc[field] = retrieved_record[field]
+ else:
+ for key, value in retrieved_record.items():
+ result_doc[key] = value
+
+ for key, value in result_doc.iteritems():
+ result_doc[key] = self._from_whoosh_format(value)
+
+ return result_doc
+
+ def _from_whoosh_format(self, value):
+ if isinstance(value, datetime):
+ value = utc.localize(value)
+ return value
+
+ def _prepare_query_result_attributes(
+ self, query, results, pagenum, pagelen):
+ results_total_num = query.execute().result.numFound
+ total_page_count = int(ceil(results_total_num / pagelen))
+ pagenum = min(total_page_count, pagenum)
+
+ offset = (pagenum-1) * pagelen
+ if (offset+pagelen) > results_total_num:
+ pagelen = results_total_num - offset
+
+ return results_total_num, total_page_count, pagenum, offset
+
+ def is_index_outdated(self):
+ return False
+
+ def recreate_index(self):
+ return True
+
+ @contextmanager
+ def start_operation(self):
+ yield
+
+ def _search_fields_for_token(self, token):
+ q_chain = None
+ field_boosts = DefaultQueryParser(self.env).field_boosts
+
+ for field, boost in field_boosts.iteritems():
+ if field != 'query_suggestion_basket' and field != 'relations':
+ field_token_dict = {field: token}
+ if q_chain is None:
+ q_chain = self.solr_interface.Q(**field_token_dict)**boost
+ else:
+ q_chain |= self.solr_interface.Q(**field_token_dict)**boost
+
+ return q_chain
+
+ def _reformat_doc(self, doc):
+ for key, value in doc.items():
+ if key is None:
+ del doc[None]
+ elif value is None:
+ del doc[key]
+ elif isinstance(value, basestring) and value == "":
+ del doc[key]
+ else:
+ doc[key] = self._to_whoosh_format(value)
+
+ def _to_whoosh_format(self, value):
+ if isinstance(value, basestring):
+ value = unicode(value)
+ elif isinstance(value, datetime):
+ value = self._convert_date_to_tz_naive_utc(value)
+ return value
+
+ def _convert_date_to_tz_naive_utc(self, value):
+ if value.tzinfo:
+ utc_time = value.astimezone(utc)
+ value = utc_time.replace(tzinfo=None)
+ return value
+
+ def _create_unique_id(self, product, doc_type, doc_id):
+ if product:
+ return u"%s:%s:%s" % (product, doc_type, doc_id)
+ else:
+ return u"%s:%s" % (doc_type, doc_id)
+
+
+
Added:
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/tests/__init__.py
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/tests/__init__.py?rev=1617747&view=auto
==============================================================================
--- bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/tests/__init__.py
(added)
+++ bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/tests/__init__.py
Wed Aug 13 16:08:04 2014
@@ -0,0 +1,18 @@
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
+
+from bhsolr.tests import (
+ backend
+)
+
+
+def suite():
+ test_suite = unittest.TestSuite()
+ return test_suite
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='suite')
+else:
+ test_suite = suite()
Added: bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/tests/backend.py
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/tests/backend.py?rev=1617747&view=auto
==============================================================================
--- bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/tests/backend.py
(added)
+++ bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/tests/backend.py
Wed Aug 13 16:08:04 2014
@@ -0,0 +1,21 @@
+import unittest
+
+from trac.test import EnvironmentStub, Mock, MockPerm
+from trac.util.datefmt import utc
+from trac.web.chrome import Chrome
+from bhsearch.tests.base import BaseBloodhoundSearchTest
+
+class SolrBackendTestCase(BaseBloodhoundSearchTest):
+ def setUp(self):
+ super(SolrBackendTestCase, self).setUp()
+ self.solr_backend = SolrBackend(self.env)
+ # self.parser = DefaultQueryParser(self.env)
+
+def suite():
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(SolrBackendTestCase))
+ return suite
+
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='suite')
Added: bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/tests/schema.py
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/tests/schema.py?rev=1617747&view=auto
==============================================================================
(empty)
Added:
bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/tests/search_resources/__init__.py
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0014_solr/bloodhound_solr/bhsolr/tests/search_resources/__init__.py?rev=1617747&view=auto
==============================================================================
(empty)
Modified: bloodhound/branches/bep_0014_solr/bloodhound_solr/setup.py
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0014_solr/bloodhound_solr/setup.py?rev=1617747&r1=1617746&r2=1617747&view=diff
==============================================================================
--- bloodhound/branches/bep_0014_solr/bloodhound_solr/setup.py (original)
+++ bloodhound/branches/bep_0014_solr/bloodhound_solr/setup.py Wed Aug 13
16:08:04 2014
@@ -1,34 +1,59 @@
+# -*- coding: UTF-8 -*-
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
from setuptools import setup, find_packages
-PKG_INFO = {'bhsolr': ['schemadoc/*.xml'],
- 'bhsolr.search_resources' : [],
- }
+PKG_INFO = {
+ 'bhsolr': ['../README', '../TESTING_README'],
+ 'bhsolr.search_resources' : [],
+ 'bhsolr.tests': ['*.*'],
+ 'bhsolr.tests.search_resources': ['*.*'],
+ }
ENTRY_POINTS = {
- 'trac.plugins': [
- 'bhsolr.admin = bhsolr.admin',
- 'bhsolr.schema = bhsolr.schema',
- 'bhsolr.backend = bhsolr.backend',
- 'bhsolr.web_ui = bhsolr.web_ui',
- 'bhsolr.search_resources.ticket_search =
bhsolr.search_resources.ticket_search',
- 'bhsolr.search_resources.milestone_search =
bhsolr.search_resources.milestone_search',
- 'bhsolr.search_resources.changeset_search =
bhsolr.search_resources.changeset_search',
- 'bhsolr.search_resources.wiki_search =
bhsolr.search_resources.wiki_search'
- ],}
+ 'trac.plugins': [
+ 'bhsolr.admin = bhsolr.admin',
+ 'bhsolr.schema = bhsolr.schema',
+ 'bhsolr.solr_backend = bhsolr.solr_backend',
+ 'bhsolr.search_resources.ticket_search = \
+ bhsolr.search_resources.ticket_search',
+ 'bhsolr.search_resources.milestone_search = \
+ bhsolr.search_resources.milestone_search',
+ 'bhsolr.search_resources.changeset_search = \
+ bhsolr.search_resources.changeset_search',
+ 'bhsolr.search_resources.wiki_search = bhsolr.search_resources.wiki_search'
+ ],}
+
setup(
- name = 'BloodhoundSolrPlugin',
- version = '0.1',
- description = "Apache Solr support for Apache(TM) Bloodhound.",
- author = "Apache Bloodhound",
- license = "Apache License v2",
- url = "http://bloodhound.apache.org/",
- requires = ['trac', 'lxml', 'sunburnt', 'httplib2'],
- packages = find_packages(),
- package_data = PKG_INFO,
- include_package_data=True,
- entry_points = ENTRY_POINTS,
- test_suite='bhsolr.tests.test_suite',
-)
+ name = 'BloodhoundSolrPlugin',
+ version = '0.1',
+ description = "Apache Solr support for Apache(TM) Bloodhound.",
+ author = "Apache Bloodhound",
+ license = "Apache License v2",
+ url = "http://bloodhound.apache.org/",
+ requires = ['trac', 'lxml', 'sunburnt', 'httplib2'],
+ packages = find_packages(),
+ package_data = PKG_INFO,
+ include_package_data=True,
+ entry_points = ENTRY_POINTS,
+ test_suite='bhsolr.tests.test_suite',
+ )
Added:
bloodhound/branches/bep_0014_solr/bloodhound_theme/bhtheme/templates/bh_more_like_this.html
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0014_solr/bloodhound_theme/bhtheme/templates/bh_more_like_this.html?rev=1617747&view=auto
==============================================================================
---
bloodhound/branches/bep_0014_solr/bloodhound_theme/bhtheme/templates/bh_more_like_this.html
(added)
+++
bloodhound/branches/bep_0014_solr/bloodhound_theme/bhtheme/templates/bh_more_like_this.html
Wed Aug 13 16:08:04 2014
@@ -0,0 +1,32 @@
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:i18n="http://genshi.edgewall.org/i18n">
+
+ <body>
+ <div class="panel-group" id="accordion${doc.unique_id}">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h4 class="panel-title">
+ <a class="btn" data-toggle="collapse"
data-parent="#accordion${doc.unique_id}" href="#collapse${hexdigest}">
+ More Like This
+ </a>
+ </h4>
+ </div>
+ <div id="collapse${hexdigest}" class="panel-collapse collapse out">
+ <div class="panel-body">
+ <dl>
+ <py:for each="result in doc_mlt">
+ <dt><a href="${result.href}">${result.title}</a></dt>
+ </py:for>
+ </dl>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ </body>
+</html>
Modified: bloodhound/branches/bep_0014_solr/bloodhound_theme/bhtheme/theme.py
URL:
http://svn.apache.org/viewvc/bloodhound/branches/bep_0014_solr/bloodhound_theme/bhtheme/theme.py?rev=1617747&r1=1617746&r2=1617747&view=diff
==============================================================================
--- bloodhound/branches/bep_0014_solr/bloodhound_theme/bhtheme/theme.py
(original)
+++ bloodhound/branches/bep_0014_solr/bloodhound_theme/bhtheme/theme.py Wed Aug
13 16:08:04 2014
@@ -353,6 +353,7 @@ class BloodhoundTheme(ThemeBase):
req.search_query = data.get('query')
# Context nav
prevnext_nav(req, _('Previous'), _('Next'))
+ self._add_more_like_this(req, template, data, content_type, is_active)
# Breadcrumbs nav
data['resourcepath_template'] = 'bh_path_search.html'
@@ -451,6 +452,11 @@ class BloodhoundTheme(ThemeBase):
if isinstance(req.perm.env, ProductEnvironment):
data['resourcepath_template'] = 'bh_path_general.html'
+ def _add_more_like_this(self, req, template, data,
+ content_type, is_active):
+ """Adds a template for displaying More Like This results."""
+ data['resourcepath_template'] = 'bh_more_like_this.html'
+
def _modify_product_list(self, req, template, data, content_type,
is_active):
"""Transform products list into media list by adding